Skip to content

Commit fbb8c28

Browse files
Fix some more review comments.
1 parent c443529 commit fbb8c28

28 files changed

Lines changed: 333 additions & 234 deletions

File tree

14.1 KB
Loading

docs/en_US/preferences.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,12 +309,21 @@ Use the fields on the *User Interface* panel to set the user interface related p
309309
this setting is False, meaning that Query Tool/PSQL tabs will open in the currently
310310
active workspace (either the default or the workspace selected at the time of opening).
311311

312+
* When the *Save the application state?* option is enabled the current state of various
313+
tools—such as Query Tool, ERD, Schema Diff, and PSQL—will be saved in the encrypted
314+
format.If the application is closed unexpectedly, the tab is accidentally closed,
315+
or the page is refreshed, the saved state will be automatically restored for
316+
each respective tool.**Note:**
317+
312318
* Use the *Themes* drop-down listbox to select the theme for pgAdmin. You'll also get a preview just below the
313319
drop down. You can also submit your own themes,
314320
check `here <https://github.com/pgadmin-org/pgadmin4/blob/master/README.md>`_ how.
315321
Currently we support Light, Dark, High Contrast and System theme. Selecting System option will follow
316322
your computer's settings.
317323

324+
**Note:** Saving the application state will not preserve data for tool tabs opened in
325+
separate browser tabs when running in server mode..
326+
318327
The Paths Node
319328
**************
320329

web/pgadmin/authenticate/__init__.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,6 @@ def authenticate(self):
285285
source.get_source_name())
286286

287287
status, msg = source.authenticate(self.form)
288-
print(status)
289-
print(msg)
290288

291289
if status:
292290
self.set_current_source(source.get_source_name())
@@ -297,17 +295,6 @@ def authenticate(self):
297295
current_app.logger.debug(
298296
"Authentication initiated via source: %s is failed." %
299297
source.get_source_name())
300-
current_user = User.query.filter_by(username=username,
301-
auth_source=src).first()
302-
# get list with auth source src
303-
# iterate over it and find if user present with that
304-
if len(users) > 0 and current_user:
305-
print('User may be coming first time so continue with all possible')
306-
break
307-
elif len(users) > 0:
308-
print('User already present with other aut source break it')
309-
break
310-
311298
return status, msg
312299

313300
def login(self):

web/pgadmin/browser/static/js/browser.js

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ define('pgadmin.browser', [
212212
let save_the_workspace = prefStore.getPreferencesForModule('misc').save_app_state;
213213
if(save_the_workspace){
214214
this.restore_pgadmin_state();
215+
pgBrowser.docker.default_workspace.focus();
215216
}
216217
},
217218
check_corrupted_db_file: function() {
@@ -299,33 +300,33 @@ define('pgadmin.browser', [
299300
},
300301

301302
restore_pgadmin_state: function () {
302-
getApiInstance().get(
303+
getApiInstance({'Content-Encoding': 'gzip'}).get(
303304
url_for('settings.get_application_state')
304305
).then((res)=> {
305306
if(res.data.success && res.data.data.result.length > 0){
306-
_.each(res.data.data.result, function(tool_state){
307-
let tool_name = tool_state.tool_name;
308-
let tool_data = tool_state.tool_data;
309-
let sql_id = `${tool_name}-${getRandomInt(1, 9999999)}`;
310-
311-
if (tool_name == 'sqleditor'){
312-
localStorage.setItem(sql_id, tool_data);
313-
showQueryTool.relaunchSqlTool(tool_state, sql_id);
314-
}else if(tool_name == 'psql'){
315-
pgAdmin.Tools.Psql.openPsqlTool(null, null, tool_state);
316-
}else if(tool_name == 'ERD'){
317-
localStorage.setItem(sql_id, tool_data);
318-
pgAdmin.Tools.ERD.showErdTool(null, null, false, sql_id, tool_state);
319-
}else if(tool_name == 'schema_diff'){
320-
localStorage.setItem(sql_id, tool_data);
321-
pgAdmin.Tools.SchemaDiff.launchSchemaDiff(sql_id);
307+
_.each(res.data.data.result, function(toolState){
308+
let toolNme = toolState.tool_name;
309+
let toolData = toolState.tool_data;
310+
let toolDataId = `${toolNme}-${getRandomInt(1, 9999999)}`;
311+
let connectionInfo = toolState.connection_info;
312+
313+
if (toolNme == 'sqleditor'){
314+
localStorage.setItem(toolDataId, toolData);
315+
showQueryTool.relaunchSqlTool(connectionInfo, toolDataId);
316+
}else if(toolNme == 'psql'){
317+
pgAdmin.Tools.Psql.openPsqlTool(null, null, connectionInfo);
318+
}else if(toolNme == 'ERD'){
319+
localStorage.setItem(toolDataId, toolData);
320+
pgAdmin.Tools.ERD.showErdTool(null, null, false, connectionInfo, toolDataId);
321+
}else if(toolNme == 'schema_diff'){
322+
localStorage.setItem(toolDataId, toolData);
323+
pgAdmin.Tools.SchemaDiff.launchSchemaDiff(toolDataId);
322324
}
323325
});
324326

325327
// call clear application state data.
326328
try {
327-
getApiInstance().delete(url_for('settings.delete_application_state'), {
328-
});
329+
getApiInstance().delete(url_for('settings.delete_application_state'), {});
329330
} catch (error) {
330331
console.error(error);
331332
pgAdmin.Browser.notifier.error(gettext('Failed to remove query data.') + parseApiError(error));

web/pgadmin/misc/workspaces/static/js/AdHocConnection.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ export default function AdHocConnection({mode}) {
455455
'pgadmin:tool:show',
456456
`${BROWSER_PANELS.PSQL_TOOL}_${transId}`,
457457
openUrl,
458-
{title: escapedTitle, db: db_name},
458+
{title: escapedTitle, db: db_name, server_name: formData.server_name, 'user': user_name},
459459
{title: panelTitle, icon: 'pg-font-icon icon-terminal', manualClose: false, renamable: true},
460460
Boolean(open_new_tab?.includes('psql_tool'))
461461
);

web/pgadmin/preferences/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import json
1717
from flask import render_template, Response, request, session, current_app
1818
from flask_babel import gettext
19+
20+
from pgadmin.settings import delete_tool_data
1921
from pgadmin.user_login_check import pga_login_required
2022
from pgadmin.utils import PgAdminModule
2123
from pgadmin.utils.ajax import success_return, \
@@ -238,6 +240,9 @@ def save():
238240
data['mid'], data['category_id'], data['id'], data['value'])
239241
sgm.get_nodes(sgm)
240242

243+
if data['name'] == 'save_app_state' and not data['value']:
244+
delete_tool_data()
245+
241246
if not res:
242247
return internal_server_error(errormsg=msg)
243248

web/pgadmin/settings/__init__.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,18 @@ def get_file_format_setting():
269269
@pga_login_required
270270
def save_application_state():
271271
"""
272-
Args:
273-
sid: server id
274-
did: database id
272+
Expose an api to save the application state which stores the data from
273+
query tool, ERD, schema-diff, psql
275274
"""
276275
data = json.loads(request.data)
277-
id = data['trans_id']
276+
trans_id = data['trans_id']
278277
fernet = Fernet(current_app.config['SECRET_KEY'].encode())
279278
tool_data = fernet.encrypt(json.dumps(data['tool_data']).encode())
280279
connection_info = data['connection_info'] \
281280
if 'connection_info' in data else None
282281
try:
283282
data_entry = ApplicationState(
284-
uid=current_user.id, id=id,connection_info=connection_info,
283+
uid=current_user.id, id=trans_id,connection_info=connection_info,
285284
tool_name=data['tool_name'], tool_data=tool_data)
286285

287286
db.session.merge(data_entry)
@@ -304,6 +303,9 @@ def save_application_state():
304303
)
305304
@pga_login_required
306305
def get_application_state():
306+
"""
307+
Returns application state if any stored.
308+
"""
307309
fernet = Fernet(current_app.config['SECRET_KEY'].encode())
308310
result = db.session \
309311
.query(ApplicationState) \
@@ -335,10 +337,16 @@ def delete_application_state():
335337
if request.data:
336338
data = json.loads(request.data)
337339
trans_id = int(data['panelId'].split('_')[-1])
338-
return delete_tool_data(trans_id)
340+
status, msg = delete_tool_data(trans_id)
341+
return make_json_response(
342+
data={
343+
'status': status,
344+
'msg': msg,
345+
}
346+
)
339347

340348

341-
def delete_tool_data(trans_id):
349+
def delete_tool_data(trans_id=None):
342350
try:
343351
if trans_id:
344352
results = db.session \
@@ -354,17 +362,7 @@ def delete_tool_data(trans_id):
354362
for result in results:
355363
db.session.delete(result)
356364
db.session.commit()
357-
return make_json_response(
358-
data={
359-
'status': True,
360-
'msg': 'Success',
361-
}
362-
)
365+
return True, 'Success'
363366
except Exception as e:
364367
db.session.rollback()
365-
return make_json_response(
366-
data={
367-
'status': False,
368-
'msg': str(e),
369-
}
370-
)
368+
return False, str(e)

web/pgadmin/settings/static/ApplicationStateProvider.jsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,48 @@ import React, { useContext, useMemo } from 'react';
1010
import PropTypes from 'prop-types';
1111
import getApiInstance from '../../static/js/api_instance';
1212
import url_for from 'sources/url_for';
13+
import { getBrowser } from '../../static/js/utils';
14+
import usePreferences from '../../preferences/static/js/store';
1315

1416
const ApplicationStateContext = React.createContext();
1517

1618
export const useApplicationState = ()=>useContext(ApplicationStateContext);
1719

18-
export function retrieveDataFromLocalStorgae(sqlId){
19-
let sqlValue = JSON.parse(localStorage.getItem(sqlId));
20-
localStorage.removeItem(sqlId);
21-
return sqlValue;
20+
export function getToolData(localStorageId){
21+
let toolDataJson = JSON.parse(localStorage.getItem(localStorageId));
22+
localStorage.removeItem(localStorageId);
23+
return toolDataJson;
2224
}
2325

2426
export function ApplicationStateProvider({children}){
25-
const saveToolData = (data) =>{
26-
getApiInstance().post(
27+
const preferencesStore = usePreferences();
28+
const saveAppState = preferencesStore?.getPreferencesForModule('misc')?.save_app_state;
29+
const openNewTab = preferencesStore?.getPreferencesForModule('browser')?.new_browser_tab_open;
30+
31+
const saveToolData = (toolName, connectionInfo, transId, toolData) =>{
32+
let data = {
33+
'tool_name': toolName,
34+
'connection_info': connectionInfo,
35+
'trans_id': transId,
36+
'tool_data': toolData
37+
};
38+
getApiInstance({'Content-Encoding': 'gzip'}).post(
2739
url_for('settings.save_application_state'),
2840
JSON.stringify(data),
2941
).catch((error)=>{console.error(error);});
3042
};
3143

44+
const enableSaveToolData = (toolName)=>{
45+
let toolMapping = {'sqleditor': 'qt', 'schema_diff': 'schema_diff', 'psql': 'psql_tool', 'ERD': 'erd_tool'};
46+
if(openNewTab?.includes(toolMapping[toolName])){
47+
return saveAppState && getBrowser().name == 'Electron';
48+
}
49+
return saveAppState;
50+
};
51+
3252
const value = useMemo(()=>({
3353
saveToolData,
54+
enableSaveToolData
3455
}), []);
3556

3657
return <ApplicationStateContext.Provider value={value}>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import PropTypes from 'prop-types';
2+
import React from 'react';
3+
import gettext from 'sources/gettext';
4+
import { LAYOUT_EVENTS } from './helpers/Layout';
5+
import EmptyPanelMessage from './components/EmptyPanelMessage';
6+
7+
export default function ToolErrorView({error, panelId, panelDocker}){
8+
9+
panelDocker.eventBus.registerListener(LAYOUT_EVENTS.CLOSING, (id)=>{
10+
if(panelId == id) {
11+
panelDocker.close(panelId, true);
12+
}
13+
});
14+
15+
let err_msg = gettext(`Unable to restore data due to error: ${error}`);
16+
return <EmptyPanelMessage error={gettext(err_msg)}/>;
17+
}
18+
19+
ToolErrorView.propTypes = {
20+
error: PropTypes.string,
21+
panelId: PropTypes.string,
22+
panelDocker: PropTypes.object,
23+
pgAdmin: PropTypes.object,
24+
toolName: PropTypes.string,
25+
};

web/pgadmin/static/js/components/EmptyPanelMessage.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { styled } from '@mui/material/styles';
1212
import { Box } from '@mui/material';
1313
import InfoRoundedIcon from '@mui/icons-material/InfoRounded';
1414
import PropTypes from 'prop-types';
15+
import { FormHelperText } from '@mui/material';
16+
import HTMLReactParse from 'html-react-parser';
1517

1618
const StyledBox = styled(Box)(({theme}) => ({
1719
color: theme.palette.text.primary,
@@ -23,16 +25,20 @@ const StyledBox = styled(Box)(({theme}) => ({
2325
height: '100%',
2426
}));
2527

26-
export default function EmptyPanelMessage({text, style}) {
28+
export default function EmptyPanelMessage({text, style, error}) {
2729

2830
return (
2931
<StyledBox style={style}>
30-
<InfoRoundedIcon style={{height: '1.2rem'}}/>
31-
<span style={{marginLeft: '4px'}}>{text}</span>
32+
{ error ? <FormHelperText variant="outlined" error= {true} style={{marginLeft: '4px'}} >{HTMLReactParse(error)}</FormHelperText> :
33+
<div>
34+
<InfoRoundedIcon style={{height: '1.2rem'}}/>
35+
<span style={{marginLeft: '4px'}}>{text}</span>
36+
</div>}
3237
</StyledBox>
3338
);
3439
}
3540
EmptyPanelMessage.propTypes = {
3641
text: PropTypes.string,
3742
style: PropTypes.object,
43+
error: PropTypes.string,
3844
};

0 commit comments

Comments
 (0)