Skip to content

Commit 52ee3ec

Browse files
Ensure proper error message shown if any error occurs while restoring psql tool.
1 parent 7c2b773 commit 52ee3ec

13 files changed

Lines changed: 181 additions & 128 deletions

File tree

docs/en_US/preferences.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ Use the fields on the *User Interface* panel to set the user interface related p
329329
format. If the application is closed unexpectedly, the tab is accidentally closed,
330330
or the page is refreshed, the saved state will be automatically restored for
331331
each respective tool. **Note:** Saving the application state will not preserve data for tool tabs opened in
332-
separate browser tabs when running in server mode.
332+
separate browser tabs when running in server mode.Any tool referring ad-hoc server connection will not be restored.
333333

334334
* Use the *Themes* drop-down listbox to select the theme for pgAdmin. You'll also get a preview just below the
335335
drop down. You can also submit your own themes,

web/pgadmin/static/js/ToolErrorView.jsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { LAYOUT_EVENTS } from './helpers/Layout';
55
import { styled } from '@mui/material/styles';
66
import { FormHelperText, Box } from '@mui/material';
77
import HTMLReactParse from 'html-react-parser';
8+
import { deleteToolData } from '../../settings/static/ApplicationStateProvider';
89

910
const StyledBox = styled(Box)(({theme}) => ({
1011
color: theme.palette.text.primary,
@@ -15,15 +16,18 @@ const StyledBox = styled(Box)(({theme}) => ({
1516
height: '100%',
1617
}));
1718

18-
export default function ToolErrorView({error, panelId, panelDocker}){
19-
19+
export default function ToolErrorView({error, panelId, panelDocker, toolDataId}){
2020
panelDocker.eventBus.registerListener(LAYOUT_EVENTS.CLOSING, (id)=>{
2121
if(panelId == id) {
2222
panelDocker.close(panelId, true);
23+
if(toolDataId){
24+
let transId = toolDataId.replace('-','_');
25+
deleteToolData(transId, transId);
26+
}
2327
}
2428
});
2529

26-
let err_msg = gettext(`There was some error while opening: ${error}`);
30+
let err_msg = gettext(`An error occurred while opening the tool: ${error}`);
2731
return (<StyledBox>
2832
<FormHelperText variant="outlined" error= {true} style={{marginLeft: '4px'}} >{HTMLReactParse(err_msg)}</FormHelperText>
2933
</StyledBox>);
@@ -33,4 +37,5 @@ ToolErrorView.propTypes = {
3337
error: PropTypes.string,
3438
panelId: PropTypes.string,
3539
panelDocker: PropTypes.object,
40+
toolDataId: PropTypes.string
3641
};

web/pgadmin/tools/erd/__init__.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"""A blueprint module implementing the erd tool."""
1111
import json
1212

13-
from flask import request, Response
13+
from flask import request, Response, session
1414
from flask import render_template, current_app as app
1515
from flask_security import permissions_required
1616
from pgadmin.user_login_check import pga_login_required
@@ -20,7 +20,7 @@
2020
SHORTCUT_FIELDS as shortcut_fields
2121
from pgadmin.utils.ajax import make_json_response, internal_server_error
2222
from pgadmin.model import Server
23-
from config import PG_DEFAULT_DRIVER
23+
from config import PG_DEFAULT_DRIVER, ALLOW_SAVE_PASSWORD
2424
from pgadmin.utils.driver import get_driver
2525
from pgadmin.browser.utils import underscore_unescape
2626
from pgadmin.browser.server_groups.servers.databases.schemas.utils \
@@ -540,11 +540,26 @@ def initialize_erd(trans_id, sgid, sid, did):
540540
"""
541541
# Read the data if present. Skipping read may cause connection
542542
# reset error if data is sent from the client
543+
data = {}
543544
if request.data:
544-
_ = request.data
545-
546-
conn = _get_connection(sid, did, trans_id)
545+
data = json.loads(request.data)
547546

547+
try:
548+
conn = _get_connection(sid, did, trans_id, data.get('db_name', None))
549+
except ConnectionLost as e:
550+
return make_json_response(
551+
success=0,
552+
status=428,
553+
result={"server_label": data.get('server_name', None),
554+
"username": data.get('user', None),
555+
"server_type":data.get('server_type', None),
556+
"errmsg": str(e),
557+
"prompt_password": True,
558+
"allow_save_password": True
559+
if ALLOW_SAVE_PASSWORD and
560+
session.get('allow_save_password', None) else False,
561+
}
562+
)
548563
return make_json_response(
549564
data={
550565
'connId': str(trans_id),
@@ -554,7 +569,7 @@ def initialize_erd(trans_id, sgid, sid, did):
554569
)
555570

556571

557-
def _get_connection(sid, did, trans_id):
572+
def _get_connection(sid, did, trans_id, db_name=None):
558573
"""
559574
Get the connection object of ERD.
560575
:param sid:
@@ -564,9 +579,13 @@ def _get_connection(sid, did, trans_id):
564579
"""
565580
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
566581
try:
567-
conn = manager.connection(did=did, conn_id=trans_id,
582+
conn = manager.connection(conn_id=trans_id,
568583
auto_reconnect=True,
569-
use_binary_placeholder=True)
584+
use_binary_placeholder=True,
585+
**({"database": db_name}
586+
if db_name is not None
587+
else {"did": did})
588+
)
570589
status, msg = conn.connect()
571590
if not status:
572591
app.logger.error(msg)

web/pgadmin/tools/erd/static/js/ERDModule.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,19 @@ export default class ERDModule {
9696

9797
parentData = {
9898
server_group: {
99-
_id: connectionInfo.sgid || 0,
100-
server_type: connectionInfo.server_type
99+
_id: connectionInfo.sgid || 0
101100
},
102101
server: {
103102
_id: connectionInfo.sid,
103+
server_type: connectionInfo.server_type,
104+
label: connectionInfo.server_name,
105+
user: {
106+
name: connectionInfo.user
107+
}
104108
},
105109
database: {
106110
_id: connectionInfo.did,
111+
label: connectionInfo.db_name
107112
},
108113
schema: {
109114
_id: connectionInfo.scid || null,
@@ -142,7 +147,7 @@ export default class ERDModule {
142147
'pgadmin:tool:show',
143148
`${BROWSER_PANELS.ERD_TOOL}_${transId}`,
144149
panelUrl,
145-
{sql_id: toolDataId, title: _.escape(panelTitle)},
150+
{sql_id: toolDataId, title: _.escape(panelTitle), db_name:parentData.database.label, server_name: parentData.server.label, user: parentData.server.user.name, server_type: parentData.server.server_type},
146151
{title: 'Untitled', icon: 'fa fa-sitemap'},
147152
Boolean(open_new_tab?.includes('erd_tool'))
148153
);

web/pgadmin/tools/erd/static/js/erd_tool/components/ConnectionBar.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const STATUS = {
4242
function ConnectionStatusIcon({status}) {
4343
if(status == STATUS.CONNECTING) {
4444
return <CircularProgress style={{height: '18px', width: '18px'}} />;
45-
} else if(status == STATUS.CONNECTED || status == STATUS.FAILED) {
45+
} else if(status == STATUS.CONNECTED) {
4646
return <ConnectedIcon />;
4747
} else {
4848
return <DisconnectedIcon />;

web/pgadmin/tools/erd/static/js/erd_tool/components/ERDTool.jsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import BeforeUnload from './BeforeUnload';
3939
import { isMac } from '../../../../../../static/js/keyboard_shortcuts';
4040
import DownloadUtils from '../../../../../../static/js/DownloadUtils';
4141
import { getToolData } from '../../../../../../settings/static/ApplicationStateProvider';
42+
import { connectServerModal, connectServer } from '../../../../../sqleditor/static/js/components/connectServer';
4243

4344
/* Custom react-diagram action for keyboard events */
4445
export class KeyboardShortcutAction extends Action {
@@ -348,10 +349,12 @@ export default class ERDTool extends React.Component {
348349
});
349350

350351
let done = await this.initConnection();
351-
if(!done) return;
352+
if(!done && !this.props.params.sql_id) return;
352353

353-
done = await this.loadPrequisiteData();
354-
if(!done) return;
354+
if(done){
355+
done = await this.loadPrequisiteData();
356+
if(!done && !this.props.params.sql_id) return;
357+
}
355358

356359

357360
if(this.props.params.sql_id){
@@ -361,7 +364,7 @@ export default class ERDTool extends React.Component {
361364
this.diagram.clearSelection();
362365
this.registerModelEvents();
363366
this.setState({dirty: true});
364-
this.eventBus.fireEvent(ERD_EVENTS.DIRTY, true, this.serializeFile());
367+
this.eventBus.fireEvent(ERD_EVENTS.DIRTY, true, sqlValue);
365368
}
366369
}
367370
else if(this.props.params.gen) {
@@ -597,6 +600,7 @@ export default class ERDTool extends React.Component {
597600
current_file: fileName,
598601
dirty: false,
599602
});
603+
this.eventBus.fireEvent(ERD_EVENTS.DIRTY, true, res.data);
600604
this.eventBus.fireEvent(ERD_EVENTS.DIRTY, false);
601605
this.setTitle(fileName);
602606
this.diagram.deserialize(res.data);
@@ -857,7 +861,12 @@ export default class ERDTool extends React.Component {
857861
});
858862

859863
try {
860-
let response = await this.apiObj.post(initUrl);
864+
let response = await this.apiObj.post(
865+
initUrl,
866+
{server_name: this.props.params.server_name,
867+
server_type : this.props.params.server_type,
868+
user: this.props.params.user,
869+
db_name: this.props.params.db_name});
861870
this.setState({
862871
conn_status: CONNECT_STATUS.CONNECTED,
863872
server_version: response.data.data.serverVersion,
@@ -866,7 +875,16 @@ export default class ERDTool extends React.Component {
866875
return true;
867876
} catch (error) {
868877
this.setState({conn_status: CONNECT_STATUS.FAILED});
869-
this.handleAxiosCatch(error);
878+
879+
connectServerModal(this.context, error.response?.data?.result, async (passwordData)=>{
880+
await connectServer(this.apiObj, this.context, this.props.params.sid, this.props.params.sid, passwordData, async ()=>{
881+
await this.initConnection();
882+
await this.loadPrequisiteData();
883+
});
884+
}, ()=>{
885+
this.setState({conn_status: CONNECT_STATUS.FAILED});
886+
});
887+
870888
return false;
871889
} finally {
872890
this.setLoading(null);
@@ -975,6 +993,9 @@ ERDTool.propTypes = {
975993
fgcolor: PropTypes.string,
976994
gen: PropTypes.bool.isRequired,
977995
sql_id: PropTypes.string,
996+
server_name: PropTypes.string,
997+
user: PropTypes.string,
998+
db_name: PropTypes.string,
978999
}),
9791000
pgWindow: PropTypes.object.isRequired,
9801001
pgAdmin: PropTypes.object.isRequired,

web/pgadmin/tools/psql/__init__.py

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,15 @@ def panel(trans_id):
101101
s = Server.query.filter_by(id=int(params['sid'])).first()
102102
if s:
103103
data = _get_database_role(params['sid'], params['did'])
104-
params['db'] = underscore_escape(data['db_name']) \
105-
if 'db_name' in data else 'postgres'
106-
params['role'] = underscore_escape(data['role'])
104+
if data:
105+
params['db'] = underscore_escape(data['db_name']) \
106+
if 'db_name' in data else 'postgres'
107+
params['role'] = underscore_escape(data['role'])
107108
set_env_variables(is_win=_platform == 'win32')
108109
return render_template("psql/index.html",
109110
params=json.dumps(params))
110111
else:
111-
params['error'] = 'Server did not find.'
112+
params['error'] = 'The server was not found.'
112113
return render_template(
113114
"psql/index.html",
114115
params=json.dumps(params))
@@ -303,6 +304,7 @@ def read_and_forward_pty_output(sid, data):
303304
# Check user is authenticated and PSQL is enabled in config.
304305
if current_user.is_authenticated and config.ENABLE_PSQL:
305306
connection_data = []
307+
connection_successful = False
306308
try:
307309
db = ''
308310
if data['db']:
@@ -326,33 +328,39 @@ def read_and_forward_pty_output(sid, data):
326328
return
327329
connection_data = get_connection_str(psql_utility, db,
328330
manager)
331+
connection_successful = True
329332
except Exception as e:
330333
# If any error raised during the start the PSQL emit error to UI.
331334
# request.sid: This sid is socket id.
332-
sio.emit(
333-
'conn_error',
334-
{
335-
'error': 'Error while running psql command: {0}'.format(e),
336-
}, namespace='/pty', room=request.sid)
335+
error_msg = 'Error while running psql command: {0}'.format(e)
336+
if str(e) == 'Server is not connected.':
337+
error_msg = 'Error while opening psql tool: {0}'.format(e)
337338

338-
try:
339-
if str(data['sid']) not in app.config['sid_soid_mapping']:
340-
# request.sid: refer request.sid as socket id.
341-
app.config['sid_soid_mapping'][str(data['sid'])] = list()
342-
app.config['sid_soid_mapping'][str(data['sid'])].append(
343-
request.sid)
344-
else:
345-
app.config['sid_soid_mapping'][str(data['sid'])].append(
346-
request.sid)
339+
sio.emit('conn_error',
340+
{'error': error_msg},
341+
namespace='/pty',
342+
room=request.sid)
347343

348-
sio.start_background_task(read_and_forward_pty_output,
349-
request.sid, data)
350-
except Exception as e:
351-
sio.emit(
352-
'conn_error',
353-
{
354-
'error': 'Error while running psql command: {0}'.format(e),
355-
}, namespace='/pty', room=request.sid)
344+
if connection_successful:
345+
try:
346+
if str(data['sid']) not in app.config['sid_soid_mapping']:
347+
# request.sid: refer request.sid as socket id.
348+
app.config['sid_soid_mapping'][str(data['sid'])] = list()
349+
app.config['sid_soid_mapping'][str(data['sid'])].append(
350+
request.sid)
351+
else:
352+
app.config['sid_soid_mapping'][str(data['sid'])].append(
353+
request.sid)
354+
355+
sio.start_background_task(read_and_forward_pty_output,
356+
request.sid, data)
357+
except Exception as e:
358+
sio.emit(
359+
'conn_error',
360+
{'error':'Error while running psql command: {0}'.
361+
format(e)},
362+
namespace='/pty',
363+
room=request.sid)
356364
else:
357365
# Show error if user is not authenticated.
358366
sio.emit('conn_not_allow', {'sid': request.sid}, namespace='/pty',
@@ -378,12 +386,6 @@ def _get_connection(sid, data):
378386
status, msg = conn.connect()
379387
if not status:
380388
app.logger.error(msg)
381-
sio.emit(sio.emit(
382-
'conn_error',
383-
{
384-
'error': 'Error while running psql command: {0}'
385-
''.format('Server connection not present.'),
386-
}, namespace='/pty', room=request.sid))
387389
raise RuntimeError('Server is not connected.')
388390

389391
return conn, manager

web/pgadmin/tools/psql/static/js/PsqlModule.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export default class Psql {
122122
},
123123
database: {
124124
_id: connectionInfo.did,
125-
label: connectionInfo.db
125+
_label: connectionInfo.db
126126
},
127127
schema: {
128128
_id: connectionInfo.scid || null,
@@ -161,7 +161,7 @@ export default class Psql {
161161
const transId = getRandomInt(1, 9999999);
162162
// Set psql tab title as per prefrences setting.
163163
let title_data = {
164-
'database': parentData.database ? _.unescape(parentData.database.label) : 'postgres' ,
164+
'database': parentData.database ? _.unescape(parentData.database._label) : 'postgres' ,
165165
'username': parentData.server.user.name,
166166
'server': parentData.server.label,
167167
'type': 'psql_tool',

web/pgadmin/tools/sqleditor/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ def panel(trans_id):
361361
params=json.dumps(params),
362362
)
363363
else:
364-
params['error'] = 'Server did not find.'
364+
params['error'] = 'The server was not found.'
365365
return render_template(
366366
"sqleditor/index.html",
367367
title=None,

web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ export default class SQLEditor {
254254
error={params.error}
255255
panelId={`${BROWSER_PANELS.QUERY_TOOL}_${params.trans_id}`}
256256
panelDocker={panelDocker}
257+
toolDataId={params.toolDataId}
257258
/> :
258259
<QueryToolComponent params={params}
259260
pgWindow={pgWindow}

0 commit comments

Comments
 (0)