Following issues have been resolved for the new connection feature:

1. Show servers with server groups in the dropdown.
  2. Highlighted current selected connection in the new connection dropdown.
  3. Notify the user before changing the connection.

refs #3794
pull/37/head
Nikhil Mohite 2020-10-21 17:14:59 +05:30 committed by Akshay Joshi
parent 08c4deba5a
commit 275d13d40f
8 changed files with 209 additions and 118 deletions

View File

@ -1310,7 +1310,8 @@ class ServerNode(PGChildNodeView):
# Connect the Server # Connect the Server
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid) manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
manager.update(server) if not manager.connection().connected():
manager.update(server)
conn = manager.connection() conn = manager.connection()
# Get enc key # Get enc key

View File

@ -243,7 +243,6 @@ let NewConnectionDialog = {
'title': _.escape(tab_title), 'title': _.escape(tab_title),
'user': newConnCollectionModel['user'], 'user': newConnCollectionModel['user'],
'role': newConnCollectionModel['role'], 'role': newConnCollectionModel['role'],
'password': response.password,
'server_name': _.escape(response.server_name), 'server_name': _.escape(response.server_name),
'database_name': _.escape(selected_database_name), 'database_name': _.escape(selected_database_name),
'is_selected': false, 'is_selected': false,
@ -260,13 +259,12 @@ let NewConnectionDialog = {
setTimeout(function(){ setTimeout(function(){
Alertify.newConnectionDialog('Connect to server.').resizeTo(pgAdmin.Browser.stdW.md,pgAdmin.Browser.stdH.md); Alertify.newConnectionDialog('Connect to server.').resizeTo(pgAdmin.Browser.stdW.md,pgAdmin.Browser.stdH.md);
}, 500); }, 500);
}).fail(function(error) { }).fail(function() {
Alertify.alert().setting({ Alertify.alert().setting({
'title': gettext('Connection lost'), 'title': gettext('Connection lost'),
'label':gettext('Ok'), 'label':gettext('Ok'),
'message': gettext('Connection to the server has been lost.'), 'message': gettext('Connection to the server has been lost.'),
'onok': function(){ 'onok': function(){
alert(error);
//Close the window after connection is lost //Close the window after connection is lost
window.close(); window.close();
}, },

View File

@ -78,7 +78,6 @@ export default function newConnectionDialogModel(response, sgid, sid) {
server: parseInt(sid), server: parseInt(sid),
database: null, database: null,
user: null, user: null,
password: null,
server_name: server_name, server_name: server_name,
database_name: database_name, database_name: database_name,
}, },
@ -92,7 +91,63 @@ export default function newConnectionDialogModel(response, sgid, sid) {
select2: { select2: {
allowClear: false, allowClear: false,
}, },
transform: function(data) {
let group_template_options = [];
for (let key in data) {
if (data.hasOwnProperty(key)) {
group_template_options.push({'group': key, 'optval': data[key]});
}
}
return group_template_options;
},
control: Backform.Select2Control.extend({ control: Backform.Select2Control.extend({
template: _.template([
'<% if(label == false) {} else {%>',
' <label class="<%=Backform.controlLabelClassName%>"><%=label%></label>',
'<% }%>',
'<div class="<%=controlsClassName%>">',
' <select class="<%=Backform.controlClassName%> <%=extraClasses.join(\' \')%>"',
' name="<%=name%>" value="<%-value%>" <%=disabled ? "disabled" : ""%>',
' <%=required ? "required" : ""%><%= select2.multiple ? " multiple>" : ">" %>',
' <%=select2.first_empty ? " <option></option>" : ""%>',
' <% for (var i=0; i < options.length; i++) {%>',
' <% if (options[i].group) { %>',
' <% var group = options[i].group; %>',
' <% if (options[i].optval) { %> <% var option_length = options[i].optval.length; %>',
' <optgroup label="<%=group%>">',
' <% for (var subindex=0; subindex < option_length; subindex++) {%>',
' <% var option = options[i].optval[subindex]; %>',
' <option ',
' <% if (option.image) { %> data-image=<%=option.image%> <%}%>',
' <% if (option.connected) { %> data-connected=connected <%}%>',
' value=<%- formatter.fromRaw(option.value) %>',
' <% if (option.selected) {%>selected="selected"<%} else {%>',
' <% if (!select2.multiple && option.value === rawValue) {%>selected="selected"<%}%>',
' <% if (select2.multiple && rawValue && rawValue.indexOf(option.value) != -1){%>selected="selected" data-index="rawValue.indexOf(option.value)"<%}%>',
' <%}%>',
' <%= disabled ? "disabled" : ""%>><%-option.label%></option>',
' <%}%>',
' </optgroup>',
' <%}%>',
' <%} else {%>',
' <% var option = options[i]; %>',
' <option ',
' <% if (option.image) { %> data-image=<%=option.image%> <%}%>',
' <% if (option.connected) { %> data-connected=connected <%}%>',
' value=<%- formatter.fromRaw(option.value) %>',
' <% if (option.selected) {%>selected="selected"<%} else {%>',
' <% if (!select2.multiple && option.value === rawValue) {%>selected="selected"<%}%>',
' <% if (select2.multiple && rawValue && rawValue.indexOf(option.value) != -1){%>selected="selected" data-index="rawValue.indexOf(option.value)"<%}%>',
' <%}%>',
' <%= disabled ? "disabled" : ""%>><%-option.label%></option>',
' <%}%>',
' <%}%>',
' </select>',
' <% if (helpMessage && helpMessage.length) { %>',
' <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
' <% } %>',
'</div>',
].join('\n')),
connect: function(self) { connect: function(self) {
let local_self = self; let local_self = self;
@ -147,11 +202,14 @@ export default function newConnectionDialogModel(response, sgid, sid) {
local_self.model.attributes.user = null; local_self.model.attributes.user = null;
local_self.model.attributes.role = null; local_self.model.attributes.role = null;
Backform.Select2Control.prototype.onChange.apply(local_self, arguments); Backform.Select2Control.prototype.onChange.apply(local_self, arguments);
response.server_list.forEach(function(obj){ Object.keys(response.server_list).forEach(key => {
if(obj.id==self.model.changed.server) { response.server_list[key].forEach(option => {
response.server_name = obj.name; if (option.value == local_self.getValueFromDOM()) {
} response.server_name = option.label;
}
});
}); });
loadingDiv.addClass('d-none'); loadingDiv.addClass('d-none');
alertify.connectServer().destroy(); alertify.connectServer().destroy();
}) })
@ -160,8 +218,6 @@ export default function newConnectionDialogModel(response, sgid, sid) {
alertify.connectServer().destroy(); alertify.connectServer().destroy();
alertify.connectServer('Connect to server', xhr.responseJSON.result, local_self.getValueFromDOM()); alertify.connectServer('Connect to server', xhr.responseJSON.result, local_self.getValueFromDOM());
}); });
} else {
response.password = $('#password').val();
} }
} else { } else {
local_self.model.attributes.database = null; local_self.model.attributes.database = null;
@ -178,6 +234,19 @@ export default function newConnectionDialogModel(response, sgid, sid) {
render: function() { render: function() {
let self = this; let self = this;
self.connect(self); self.connect(self);
Object.keys(response.server_list).forEach(key => {
response.server_list[key].forEach(option => {
if (option.value == parseInt(sid)) {
response.server_name = option.label;
}
});
});
var transform = self.field.get('transform') || self.defaults.transform;
if (transform && _.isFunction(transform)) {
self.field.set('options', transform.bind(self, response.server_list));
} else {
self.field.set('options', response.server_list);
}
return Backform.Select2Control.prototype.render.apply(self, arguments); return Backform.Select2Control.prototype.render.apply(self, arguments);
}, },
onChange: function() { onChange: function() {
@ -200,10 +269,12 @@ export default function newConnectionDialogModel(response, sgid, sid) {
}, },
}).done(function () { }).done(function () {
Backform.Select2Control.prototype.onChange.apply(self, arguments); Backform.Select2Control.prototype.onChange.apply(self, arguments);
response.server_list.forEach(function(obj){ Object.keys(response.server_list).forEach(key => {
if(obj.id==self.model.changed.server) { response.server_list[key].forEach(option => {
response.server_name = obj.name; if (option.value == self.getValueFromDOM()) {
} response.server_name = option.label;
}
});
}); });
loadingDiv.addClass('d-none'); loadingDiv.addClass('d-none');
}).fail(function(xhr){ }).fail(function(xhr){
@ -213,17 +284,6 @@ export default function newConnectionDialogModel(response, sgid, sid) {
}, },
}), }),
options: function() {
return _.map(response.server_list, (obj) => {
if (obj.id == parseInt(sid))
response.server_name = obj.name;
return {
value: obj.id,
label: obj.name,
};
});
},
}, },
{ {
id: 'database', id: 'database',
@ -302,27 +362,6 @@ export default function newConnectionDialogModel(response, sgid, sid) {
url: 'sqleditor.get_new_connection_role', url: 'sqleditor.get_new_connection_role',
disabled: false, disabled: false,
}, },
/*{
id: 'password',
name: 'password',
label: gettext('Password'tools/sqleditor/__init__.py),
type: 'password',
editable: true,
disabled: true,
deps: ['user'],
control: Backform.InputControl.extend({
render: function() {
let self = this;
self.model.attributes.password = null;
Backform.InputControl.prototype.render.apply(self, arguments);
return self;
},
onChange: function() {
let self = this;
Backform.InputControl.prototype.onChange.apply(self, arguments);
},
}),
},*/
], ],
validate: function() { validate: function() {
let msg = null; let msg = null;
@ -336,11 +375,6 @@ export default function newConnectionDialogModel(response, sgid, sid) {
this.errorModel.set('user', msg); this.errorModel.set('user', msg);
return msg; return msg;
} }
/*else if((this.attributes.password == '' || _.isUndefined(this.get('password')) || _.isNull(this.get('password')))) {
msg = gettext('Please enter password');
this.errorModel.set('password', msg);
return msg;
}*/
return null; return null;
}, },
}); });

View File

@ -98,6 +98,18 @@ class DebuggerModule(PgAdminModule):
) )
) )
self.tab_title = self.preference.register(
'display', 'debugger_tab_title_placeholder',
gettext("Debugger tab title placeholder"),
'text', '%FUNCTION%/%SCHEMA%/%DATABASE%',
category_label=PREF_LABEL_DISPLAY,
help_str=gettext(
'Supported placeholders: FUNCTION, SCHEMA and DATABASE. '
'You can also provide any string with or '
'without placeholders'
)
)
self.preference.register( self.preference.register(
'keyboard_shortcuts', 'btn_start', 'keyboard_shortcuts', 'btn_start',
gettext('Accesskey (Continue/Start)'), 'keyboardshortcut', gettext('Accesskey (Continue/Start)'), 'keyboardshortcut',

View File

@ -46,7 +46,7 @@ from pgadmin.tools.sqleditor.utils.macros import get_macros,\
get_user_macros, set_macros get_user_macros, set_macros
from pgadmin.utils.constants import MIMETYPE_APP_JS, \ from pgadmin.utils.constants import MIMETYPE_APP_JS, \
SERVER_CONNECTION_CLOSED, ERROR_MSG_TRANS_ID_NOT_FOUND, ERROR_FETCHING_DATA SERVER_CONNECTION_CLOSED, ERROR_MSG_TRANS_ID_NOT_FOUND, ERROR_FETCHING_DATA
from pgadmin.model import Server from pgadmin.model import Server, ServerGroup
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
MODULE_NAME = 'sqleditor' MODULE_NAME = 'sqleditor'
@ -1489,10 +1489,14 @@ def get_new_connection_data(sgid, sid=None):
:extract_sql_from_network_parameters, :extract_sql_from_network_parameters,
""" """
try: try:
# if sid and not did: server_groups = ServerGroup.query.all()
server_group_data = {server_group.name: [] for server_group in
server_groups}
servers = Server.query.all() servers = Server.query.all()
server_list = [
{'name': server.serialize['name'], "id": server.serialize['id']} [server_group_data[server.servers.name].append(
{'label': server.serialize['name'],
"value": server.serialize['id']})
for server in servers] for server in servers]
msg = "Success" msg = "Success"
@ -1501,7 +1505,7 @@ def get_new_connection_data(sgid, sid=None):
'status': True, 'status': True,
'msg': msg, 'msg': msg,
'result': { 'result': {
'server_list': server_list 'server_list': server_group_data
} }
} }
) )

View File

@ -173,8 +173,13 @@ define('tools.querytool', [
var dropdownElement = document.getElementById('connections-list'); var dropdownElement = document.getElementById('connections-list');
dropdownElement.innerHTML = ''; dropdownElement.innerHTML = '';
data_list.forEach((option, index) => { data_list.forEach((option, index) => {
$('#connections-list').append('<li class="connection-list-item" data-index='+ index +'><a class="dropdown-item" href="#" tabindex="0">'+ option.title +'</a></li>'); var opt = '';
if ('is_selected' in option && option['is_selected']) {
opt = '<li class="connection-list-item selected-connection" data-index='+ index +'><a class="dropdown-item" href="#" tabindex="0">'+ option.title +'</a></li>';
} else {
opt = '<li class="connection-list-item" data-index='+ index +'><a class="dropdown-item" href="#" tabindex="0">'+ option.title +'</a></li>';
}
$('#connections-list').append(opt);
}); });
var self = this; var self = this;
$('.connection-list-item').click(function() { $('.connection-list-item').click(function() {
@ -2131,7 +2136,6 @@ define('tools.querytool', [
on_change_connection: function(connection_details, ref) { on_change_connection: function(connection_details, ref) {
if(!connection_details['is_selected']) { if(!connection_details['is_selected']) {
var self = this; var self = this;
self.set_selected_option(connection_details);
var loadingDiv = null; var loadingDiv = null;
var msgDiv = null; var msgDiv = null;
if(ref){ if(ref){
@ -2145,66 +2149,78 @@ define('tools.querytool', [
msgDiv = loadingDiv.find('.sql-editor-busy-text'); msgDiv = loadingDiv.find('.sql-editor-busy-text');
} }
$.ajax({ alertify.confirm(gettext('Change connection'),
url: url_for('datagrid.update_query_tool_connection', { gettext('By changing the connection you will lose all your unsaved data for the current connection. <br> Do you want to continue?'),
'trans_id': self.transId, function() {
'sgid': connection_details['server_group'], self.set_selected_option(connection_details);
'sid': connection_details['server'], $.ajax({
'did': connection_details['database'], url: url_for('datagrid.update_query_tool_connection', {
}), 'trans_id': self.transId,
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(connection_details),
})
.done(function(res) {
if(res.success) {
self.transId = res.data.tran_id;
self.handler.transId = res.data.tran_id;
self.handler.url_params = {
'did': connection_details['database'],
'is_query_tool': self.handler.url_params.is_query_tool,
'server_type': self.handler.url_params.server_type,
'sgid': connection_details['server_group'], 'sgid': connection_details['server_group'],
'sid': connection_details['server'], 'sid': connection_details['server'],
'title': connection_details['title'], 'did': connection_details['database'],
}; }),
self.set_editor_title(_.unescape(self.handler.url_params.title)); method: 'POST',
self.handler.setTitle(_.unescape(self.handler.url_params.title)); contentType: 'application/json',
let success_msg = connection_details['server_name'] + '/' + connection_details['database_name'] + '- Database connected'; data: JSON.stringify(connection_details),
alertify.success(success_msg); })
if(ref){ .done(function(res) {
let connection_data = { if(res.success) {
'server_group': self.handler.url_params.sgid, self.transId = res.data.tran_id;
'server': connection_details['server'], self.handler.transId = res.data.tran_id;
'database': connection_details['database'], self.handler.url_params = {
'user': connection_details['user'], 'did': connection_details['database'],
'title': connection_details['title'], 'is_query_tool': self.handler.url_params.is_query_tool,
'role': connection_details['role'], 'server_type': self.handler.url_params.server_type,
'password': connection_details['password'], 'sgid': connection_details['server_group'],
'is_allow_new_connection': true, 'sid': connection_details['server'],
'database_name': connection_details['database_name'], 'title': connection_details['title'],
'server_name': connection_details['server_name'], };
'is_selected': true, self.set_editor_title(_.unescape(self.handler.url_params.title));
}; self.handler.setTitle(_.unescape(self.handler.url_params.title));
self.connection_list.unshift(connection_data); let success_msg = connection_details['server_name'] + '/' + connection_details['database_name'] + '- Database connected';
self.render_connection(self.connection_list); alertify.success(success_msg);
loadingDiv.addClass('d-none'); if(ref){
alertify.newConnectionDialog().destroy(); let connection_data = {
ref.close(); 'server_group': self.handler.url_params.sgid,
} else { 'server': connection_details['server'],
loadingDiv.addClass('d-none'); 'database': connection_details['database'],
} 'user': connection_details['user'],
} 'title': connection_details['title'],
return true; 'role': connection_details['role'],
}) 'is_allow_new_connection': true,
.fail(function(xhr) { '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);
loadingDiv.addClass('d-none');
alertify.newConnectionDialog().destroy();
ref.close();
} else {
loadingDiv.addClass('d-none');
}
}
return true;
})
.fail(function(xhr) {
if(xhr.status == 428) {
alertify.connectServer('Connect to server', xhr.responseJSON.result, connection_details['server'], false);
} else {
alertify.error(xhr.responseJSON['errormsg']);
}
});
},
function() {
loadingDiv.addClass('d-none'); loadingDiv.addClass('d-none');
if(xhr.status == 428) { alertify.newConnectionDialog().destroy();
alertify.connectServer('Connect to server', xhr.responseJSON.result, connection_details['server'], false); return true;
} else { }
alertify.error(xhr.responseJSON['errormsg']); ).set('labels', {
} ok: gettext('Yes'),
}); cancel: gettext('No'),
});
} }
}, },
}); });
@ -2542,7 +2558,7 @@ define('tools.querytool', [
'server_group': self.gridView.handler.url_params.sgid, 'server_group': self.gridView.handler.url_params.sgid,
'server': self.gridView.handler.url_params.sid, 'server': self.gridView.handler.url_params.sid,
'database': self.gridView.handler.url_params.did, 'database': self.gridView.handler.url_params.did,
'user': null, 'user': server_data.data.user.name,
'role': null, 'role': null,
'title': _.unescape(url_params.title), 'title': _.unescape(url_params.title),
'is_allow_new_connection': false, 'is_allow_new_connection': false,

View File

@ -371,6 +371,9 @@ div.strikeout:after {
height: 100%; height: 100%;
} }
.selected-connection {
background-color: $color-primary-light;
}
/* Setting it to hardcoded white as the SVG generated is having white bg /* Setting it to hardcoded white as the SVG generated is having white bg
* Need to check what can be done. * Need to check what can be done.

View File

@ -326,6 +326,29 @@ def register_query_tool_preferences(self):
) )
) )
self.qt_tab_title = self.preference.register(
'display', 'qt_tab_title_placeholder',
gettext("Query tool tab title placeholder"),
'text', '%DATABASE%/%USERNAME%@%SERVER%',
category_label=PREF_LABEL_DISPLAY,
help_str=gettext(
'Supported placeholders: DATABASE, USERNAME and SERVER. '
'You can also provide any string with or without placeholders.'
)
)
self.ve_edt_tab_title = self.preference.register(
'display', 'vw_edt_tab_title_placeholder',
gettext("View/Edit tab title placeholder"),
'text', '%SCHEMA%.%TABLE%/%DATABASE%/%USERNAME%@%SERVER%',
category_label=PREF_LABEL_DISPLAY,
help_str=gettext(
'Supported placeholders: SCHEMA, TABLE, DATABASE, USERNAME and '
'SERVER. You can also provide any string with or '
'without placeholders.'
)
)
self.connection_status = self.preference.register( self.connection_status = self.preference.register(
'display', 'connection_status_fetch_time', 'display', 'connection_status_fetch_time',
gettext("Connection status refresh rate"), 'integer', 2, gettext("Connection status refresh rate"), 'integer', 2,