Skip to content

Commit 8063e5e

Browse files
Ensure duplicate modal dialogs are not triggered.#8316
1 parent f25cde8 commit 8063e5e

File tree

14 files changed

+102
-50
lines changed

14 files changed

+102
-50
lines changed

runtime/src/js/pgadmin.js

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ let startPageUrl = null;
3131
let serverCheckUrl = null;
3232
let pgAdminMainScreen = null;
3333

34+
let configureWindow = null,
35+
viewLogWindow = null;
36+
3437
let serverPort = 5050;
3538
let appStartTime = (new Date()).getTime();
3639
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -77,7 +80,8 @@ contextMenu({
7780
Menu.setApplicationMenu(null);
7881

7982
function openConfigure() {
80-
const win = new BrowserWindow({
83+
if (configureWindow === null){
84+
configureWindow = new BrowserWindow({
8185
show: false,
8286
width: 600,
8387
height: 580,
@@ -88,11 +92,12 @@ function openConfigure() {
8892
preload: path.join(__dirname, 'other_preload.js'),
8993
},
9094
});
91-
win.loadFile('./src/html/configure.html');
92-
win.once('ready-to-show', ()=>{
93-
win.show();
95+
configureWindow.loadFile('./src/html/configure.html');
96+
configureWindow.once('ready-to-show', ()=>{
97+
configureWindow.show();
9498
});
9599
}
100+
}
96101

97102
function showErrorDialog(intervalID) {
98103
if(!splashWindow.isVisible()) {
@@ -304,21 +309,23 @@ function launchPgAdminWindow() {
304309

305310
setupMenu(pgAdminMainScreen, {
306311
'view_logs': ()=>{
307-
const win = new BrowserWindow({
308-
show: false,
309-
width: 800,
310-
height: 460,
311-
position: 'center',
312-
resizable: false,
313-
icon: '../../assets/pgAdmin4.png',
314-
webPreferences: {
315-
preload: path.join(__dirname, 'other_preload.js'),
316-
},
317-
});
318-
win.loadFile('./src/html/view_log.html');
319-
win.once('ready-to-show', ()=>{
320-
win.show();
321-
});
312+
if(viewLogWindow === null){
313+
viewLogWindow = new BrowserWindow({
314+
show: false,
315+
width: 800,
316+
height: 460,
317+
position: 'center',
318+
resizable: false,
319+
icon: '../../assets/pgAdmin4.png',
320+
webPreferences: {
321+
preload: path.join(__dirname, 'other_preload.js'),
322+
},
323+
});
324+
viewLogWindow.loadFile('./src/html/view_log.html');
325+
viewLogWindow.once('ready-to-show', ()=>{
326+
viewLogWindow.show();
327+
});
328+
}
322329
},
323330
'configure': openConfigure,
324331
'reloadApp': reloadApp,

web/pgadmin/about/static/js/about.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import gettext from 'sources/gettext';
1212
import pgAdmin from 'sources/pgadmin';
1313
import AboutComponent from './AboutComponent';
1414
import current_user from 'pgadmin.user_management.current_user';
15+
import { MODAL_DIALOGS } from '../../../browser/static/js/constants';
1516

1617
class About {
1718
static instance;
@@ -39,11 +40,12 @@ class About {
3940
dlgHeight = 300;
4041
}
4142

43+
const modalId = MODAL_DIALOGS.ABOUT;
4244
// Render About component
4345
pgAdmin.Browser.notifier.showModal(gettext('About %s', pgAdmin.Browser.utils.app_name), () => {
4446
return <AboutComponent />;
4547
}, { isFullScreen: false, isResizeable: true, showFullScreen: true,
46-
isFullWidth: true, dialogWidth: dlgWidth, dialogHeight: dlgHeight, minHeight: dlgHeight
48+
isFullWidth: true, dialogWidth: dlgWidth, dialogHeight: dlgHeight, minHeight: dlgHeight, modalId:modalId
4749
});
4850
}
4951
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ export const BROWSER_PANELS = {
4646
WELCOME_PSQL_TOOL: 'id-welcome-psql'
4747
};
4848

49+
export const MODAL_DIALOGS = {
50+
PREFERENCES: 'id-preferences',
51+
ABOUT: 'id-about',
52+
DEBUGGER: 'id-debugger',
53+
CONNECT_SERVER: 'id-connect-server',
54+
MASTER_PASSWORD: 'id-master-password',
55+
CHNAGE_PASSWORD: 'id-change-password',
56+
CHANGE_OWNER: 'id-change-owner',
57+
QUICK_SEARCH: 'id-quick-search',
58+
USER_MANAGEMENT: 'id-user-management',
59+
RESET_PREFERNCES: 'id-reset-preferences',
60+
QT_CONFIRMATIONS: 'id-qt-close-confirmation-',
61+
APP_QUIT: 'id-app-quit'
62+
};
63+
4964
export const WORKSPACES = {
5065
DEFAULT: 'default_workspace',
5166
QUERY_TOOL: 'query_tool_workspace',

web/pgadmin/preferences/static/js/components/PreferencesComponent.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import BaseUISchema from 'sources/SchemaView/base_schema.ui';
2929
import { getBinaryPathSchema } from '../../../../browser/server_groups/servers/static/js/binary_path.ui';
3030
import usePreferences from '../store';
3131
import { getBrowser } from '../../../../static/js/utils';
32+
import { MODAL_DIALOGS } from '../../../../browser/static/js/constants';
3233

3334

3435
const StyledBox = styled(Box)(({theme}) => ({
@@ -689,7 +690,7 @@ export default function PreferencesComponent({ ...props }) {
689690
const text = `${gettext('All preferences will be reset to their default values.')}<br><br>${gettext('Do you want to proceed?')}<br><br>
690691
${gettext('Note:')}<br> <ul style="padding-left:20px"><li style="list-style-type:disc">${gettext('The object explorer tree will be refreshed automatically to reflect the changes.')}</li>
691692
<li style="list-style-type:disc">${gettext('If the application language changes, a reload of the application will be required. You can choose to reload later at your convenience.')}</li></ul>`;
692-
693+
const modalId = MODAL_DIALOGS.RESET_PREFERNCES;
693694
pgAdmin.Browser.notifier.showModal(
694695
gettext('Reset all preferences'),
695696
(closeModal)=>{
@@ -710,7 +711,7 @@ ${gettext('Note:')}<br> <ul style="padding-left:20px"><li style="list-style-type
710711
</StyledBox>
711712
);
712713
},
713-
{ isFullScreen: false, isResizeable: false, showFullScreen: false, isFullWidth: false, showTitle: true},
714+
{ isFullScreen: false, isResizeable: false, showFullScreen: false, isFullWidth: false, showTitle: true, modalId:modalId},
714715
);
715716
};
716717

web/pgadmin/preferences/static/js/preferences.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import gettext from 'sources/gettext';
1212
import PreferencesComponent from './components/PreferencesComponent';
1313
import PreferencesTree from './components/PreferencesTree';
1414
import pgAdmin from 'sources/pgadmin';
15+
import { MODAL_DIALOGS } from '../../../browser/static/js/constants';
1516

1617
export default class Preferences {
1718
static instance;
@@ -48,14 +49,14 @@ export default class Preferences {
4849

4950
// This is a callback function to show preferences.
5051
show() {
51-
52+
const modalId = MODAL_DIALOGS.PREFERENCES;
5253
// Render Preferences component
5354
pgAdmin.Browser.notifier.showModal(gettext('Preferences'), (closeModal) => {
5455
return <PreferencesComponent
5556
renderTree={(prefTreeData) => {
5657
// Render preferences tree component
5758
return <PreferencesTree pgBrowser={this.pgBrowser} data={prefTreeData} />;
5859
}} closeModal={closeModal} />;
59-
}, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: 900, dialogHeight: 550 });
60+
}, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: 900, dialogHeight: 550, modalId: modalId });
6061
}
6162
}

web/pgadmin/static/js/BrowserComponent.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import pgWindow from 'sources/window';
3333
import WorkspaceToolbar from '../../misc/workspaces/static/js/WorkspaceToolbar';
3434
import { useWorkspace, WorkspaceProvider } from '../../misc/workspaces/static/js/WorkspaceProvider';
3535
import { PgAdminProvider, usePgAdmin } from './PgAdminProvider';
36+
import { MODAL_DIALOGS } from '../../browser/static/js/constants';
3637

3738

3839
const objectExplorerGroup = {
@@ -151,15 +152,19 @@ export default function BrowserComponent({pgAdmin}) {
151152
let { name: browser } = useMemo(()=>getBrowser(), []);
152153
const [uiReady, setUiReady] = useState(false);
153154
const confirmOnClose = getPreferencesForModule('browser').confirm_on_refresh_close;
154-
155+
const modalId = MODAL_DIALOGS.APP_QUIT;
155156
useBeforeUnload({
156157
enabled: confirmOnClose,
157158
beforeClose: (forceClose)=>{
158159
pgAdmin.Browser.notifier.confirm(
159160
gettext('Quit pgAdmin 4'),
160161
gettext('Are you sure you want to quit the application?'),
161162
function() { forceClose(); },
162-
function() { return true;},
163+
function() { return true; },
164+
gettext('Yes'),
165+
gettext('No'),
166+
'default',
167+
modalId
163168
);
164169
},
165170
isNewTab: true,

web/pgadmin/static/js/Dialogs/index.jsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import RenameTabContent from './RenameTabContent';
2323
import { BROWSER_PANELS } from '../../../browser/static/js/constants';
2424
import ErrorBoundary from '../helpers/ErrorBoundary';
2525
import QuickSearch from '../QuickSearch';
26+
import { MODAL_DIALOGS } from '../../../browser/static/js/constants';
2627

2728
// This functions is used to show the connect server password dialog.
2829
export function showServerPassword() {
@@ -36,6 +37,7 @@ export function showServerPassword() {
3637
onSuccess = arguments[7],
3738
onFailure = arguments[8];
3839

40+
const modalId = MODAL_DIALOGS.CONNECT_SERVER;
3941
pgAdmin.Browser.notifier.showModal(title, (onClose) => {
4042
return (
4143
<ConnectServerContent
@@ -67,7 +69,7 @@ export function showServerPassword() {
6769
}}
6870
/>
6971
);
70-
});
72+
}, {modalId: modalId});
7173
}
7274

7375
function masterPassCallbacks(masterpass_callback_queue) {
@@ -136,6 +138,7 @@ export function showMasterPassword(isPWDPresent, errmsg, masterpass_callback_que
136138
);}
137139
}else{
138140

141+
const modalId = MODAL_DIALOGS.MASTER_PASSWORD;
139142
pgAdmin.Browser.notifier.showModal(title, (onClose)=> {
140143
return (
141144
<MasterPasswordContent
@@ -176,7 +179,7 @@ export function showMasterPassword(isPWDPresent, errmsg, masterpass_callback_que
176179
}}
177180
/>
178181
);
179-
});
182+
}, {modalId: modalId});
180183
}
181184
}
182185

@@ -230,6 +233,7 @@ export function showChangeServerPassword() {
230233

231234
export function showChangeUserPassword(url) {
232235
const title = gettext('Change pgAdmin User Password');
236+
const modalId = MODAL_DIALOGS.CHNAGE_PASSWORD;
233237
pgAdmin.Browser.notifier.showModal(title, (onClose) => {
234238
return <ChangePasswordContent
235239
getInitData={()=>{
@@ -275,7 +279,7 @@ export function showChangeUserPassword(url) {
275279
/>;
276280
},
277281
{ isFullScreen: false, isResizeable: true, showFullScreen: false, isFullWidth: true,
278-
dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md});
282+
dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md, modalId: modalId});
279283
}
280284

281285
export function showNamedRestorePoint() {
@@ -318,6 +322,7 @@ export function showChangeOwnership() {
318322
deleteUserRow = arguments[4];
319323

320324
// Render Preferences component
325+
const modalId = MODAL_DIALOGS.CHANGE_OWNER;
321326
pgAdmin.Browser.notifier.showModal(title, (onClose) => {
322327
return <ChangeOwnershipContent
323328
onClose={()=>{
@@ -351,7 +356,7 @@ export function showChangeOwnership() {
351356
/>;
352357
},
353358
{ isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true,
354-
dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md});
359+
dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md, modalId: modalId});
355360
}
356361

357362
export function showUrlDialog() {
@@ -385,9 +390,10 @@ export function showRenameTab(panelId, panelDocker) {
385390
}
386391

387392
export function showQuickSearch() {
393+
const modalId = MODAL_DIALOGS.QUICK_SEARCH;
388394
pgAdmin.Browser.notifier.showModal(gettext('Quick Search'), (closeModal) => {
389395
return <QuickSearch closeModal={closeModal}/>;
390396
},
391-
{ isFullScreen: false, isResizeable: false, showFullScreen: false, isFullWidth: false, showTitle: false}
397+
{ isFullScreen: false, isResizeable: false, showFullScreen: false, isFullWidth: false, showTitle: false, modalId: modalId}
392398
);
393399
}

web/pgadmin/static/js/helpers/ModalProvider.jsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ function alert(title, text, onOkClick, okLabel = gettext('OK')) {
8383
});
8484
}
8585

86-
function confirm(title, text, onOkClick, onCancelClick, okLabel = gettext('Yes'), cancelLabel = gettext('No'), okIcon = 'default') {
86+
function confirm(title, text, onOkClick, onCancelClick, okLabel = gettext('Yes'), cancelLabel = gettext('No'), okIcon = 'default', modalId=null) {
8787
// bind the modal provider before calling
8888
this.showModal(title, (closeModal) => {
8989
const onCancelClickClose = () => {
@@ -98,7 +98,7 @@ function confirm(title, text, onOkClick, onCancelClick, okLabel = gettext('Yes')
9898
return (
9999
<AlertContent text={text} confirm onOkClick={onOkClickClose} onCancelClick={onCancelClickClose} okLabel={okLabel} cancelLabel={cancelLabel} okIcon={okIcon}/>
100100
);
101-
});
101+
}, {modalId: modalId});
102102
}
103103

104104
function confirmDelete(title, text, onDeleteClick, onCancelClick, deleteLabel = gettext('Delete'), cancelLabel = gettext('Cancel')) {
@@ -127,16 +127,23 @@ function confirmDelete(title, text, onDeleteClick, onCancelClick, deleteLabel =
127127

128128
export default function ModalProvider({ children }) {
129129
const [modals, setModals] = React.useState([]);
130-
131130
const showModal = (title, content, modalOptions) => {
132131
let id = getEpoch().toString() + crypto.getRandomValues(new Uint8Array(4));
133-
setModals((prev) => [...prev, {
134-
id: id,
135-
title: title,
136-
content: content,
137-
...modalOptions,
138-
}]);
132+
if(modalOptions?.modalId){
133+
id = modalOptions.modalId;
134+
}
135+
setModals((prev) => {
136+
if(prev?.find(modal=> modal.id === modalOptions?.modalId)){
137+
return [...prev];
138+
}
139+
return [...prev, {
140+
id: id,
141+
title: title,
142+
content: content,
143+
...modalOptions,
144+
}];});
139145
};
146+
140147
const closeModal = (id) => {
141148
setModals((prev) => {
142149
return prev.filter((o) => o.id != id);

web/pgadmin/static/js/helpers/Notifier.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,10 @@ class Notifier {
175175
this.modal.alert(title, text, onOkClick, okLabel);
176176
}
177177

178-
confirm(title, text, onOkClick, onCancelClick, okLabel=gettext('Yes'), cancelLabel=gettext('No'), okIcon='default') {
178+
confirm(title, text, onOkClick, onCancelClick, okLabel=gettext('Yes'), cancelLabel=gettext('No'), okIcon='default', modalId=null) {
179179
/* Use this if you want to use pgAdmin global notifier.
180180
Or else, if you want to use modal inside iframe only then use ModalProvider eg- query tool */
181-
this.modal.confirm(title, text, onOkClick, onCancelClick, okLabel, cancelLabel, okIcon);
181+
this.modal.confirm(title, text, onOkClick, onCancelClick, okLabel, cancelLabel, okIcon, modalId);
182182
}
183183

184184
confirmDelete(title, text, onDeleteClick, onCancelClick, okLabel = gettext('Delete'), cancelLabel = gettext('Cancel')){

web/pgadmin/tools/debugger/static/js/debugger_ui.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import React from 'react';
1111

1212
import gettext from 'sources/gettext';
1313
import pgAdmin from 'sources/pgadmin';
14-
14+
import { MODAL_DIALOGS } from '../../../../browser/static/js/constants';
1515
import DebuggerArgumentComponent from './components/DebuggerArgumentComponent';
1616

1717
export default class FunctionArguments {
@@ -25,9 +25,10 @@ export default class FunctionArguments {
2525
return;
2626

2727
let treeInfo = t.getTreeNodeHierarchy(i);
28+
const modalId = MODAL_DIALOGS.DEBUGGER;
2829
// Render Debugger argument component
2930
pgAdmin.Browser.notifier.showModal(gettext('Debugger'), (closeModal) => {
3031
return <DebuggerArgumentComponent closeModal={closeModal} debuggerInfo={debugInfo} restartDebug={restartDebug} isEdbProc={isEdbProc} transId={transId} pgTreeInfo={treeInfo} pgData={d}></DebuggerArgumentComponent>;
31-
}, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md });
32+
}, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md, modalId:modalId});
3233
}
3334
}

0 commit comments

Comments
 (0)