Skip to content

Commit 3b37565

Browse files
authored
fix(SaveQueryDialog): should not duplicate component in DOM (#1649)
1 parent 8887b75 commit 3b37565

File tree

4 files changed

+65
-35
lines changed

4 files changed

+65
-35
lines changed

src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22

3+
import NiceModal from '@ebay/nice-modal-react';
34
import {isEqual} from 'lodash';
45
import throttle from 'lodash/throttle';
56
import type Monaco from 'monaco-editor';
@@ -54,7 +55,7 @@ import {ExplainResult} from '../ExplainResult/ExplainResult';
5455
import {Preview} from '../Preview/Preview';
5556
import {QueryEditorControls} from '../QueryEditorControls/QueryEditorControls';
5657
import {QuerySettingsDialog} from '../QuerySettingsDialog/QuerySettingsDialog';
57-
import {SaveQueryDialog} from '../SaveQuery/SaveQuery';
58+
import {SAVE_QUERY_DIALOG} from '../SaveQuery/SaveQuery';
5859
import i18n from '../i18n';
5960

6061
import {useEditorOptions} from './helpers';
@@ -289,7 +290,7 @@ export default function QueryEditor(props: QueryEditorProps) {
289290
label: i18n('action.save-query'),
290291
keybindings: [keybindings.saveQuery],
291292
run: () => {
292-
dispatch(setQueryAction('save'));
293+
NiceModal.show(SAVE_QUERY_DIALOG);
293294
},
294295
});
295296
};
@@ -368,7 +369,6 @@ export default function QueryEditor(props: QueryEditorProps) {
368369
/>
369370
</div>
370371
</SplitPane>
371-
<SaveQueryDialog />
372372
<QuerySettingsDialog />
373373
</div>
374374
);

src/containers/Tenant/Query/SaveQuery/SaveQuery.tsx

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import React from 'react';
22

3+
import NiceModal from '@ebay/nice-modal-react';
34
import type {ButtonProps} from '@gravity-ui/uikit';
45
import {Button, Dialog, DropdownMenu, TextInput} from '@gravity-ui/uikit';
56

67
import {
78
clearQueryNameToEdit,
89
saveQuery,
9-
selectQueryAction,
1010
selectQueryName,
1111
setQueryAction,
1212
} from '../../../../store/reducers/queryActions/queryActions';
@@ -24,20 +24,25 @@ interface SaveQueryProps {
2424
buttonProps?: ButtonProps;
2525
}
2626

27-
function useSaveQueryHandler() {
27+
function useSaveQueryHandler(dialogProps?: SaveQueryDialogCommonProps) {
2828
const dispatch = useTypedDispatch();
2929
const onSaveQueryClick = React.useCallback(() => {
30-
dispatch(setQueryAction('save'));
30+
NiceModal.show(SAVE_QUERY_DIALOG, dialogProps);
3131
dispatch(clearQueryNameToEdit());
32-
}, [dispatch]);
32+
}, [dispatch, dialogProps]);
3333

3434
return onSaveQueryClick;
3535
}
3636

37-
export function SaveQueryButton(props: ButtonProps) {
38-
const onSaveQueryClick = useSaveQueryHandler();
37+
interface SaveQueryButtonProps extends ButtonProps {
38+
dialogProps?: SaveQueryDialogCommonProps;
39+
}
40+
41+
export function SaveQueryButton({dialogProps, ...buttonProps}: SaveQueryButtonProps) {
42+
const onSaveQueryClick = useSaveQueryHandler(dialogProps);
43+
3944
return (
40-
<Button onClick={onSaveQueryClick} {...props}>
45+
<Button onClick={onSaveQueryClick} {...buttonProps}>
4146
{i18n('action.save')}
4247
</Button>
4348
);
@@ -80,15 +85,19 @@ export function SaveQuery({buttonProps = {}}: SaveQueryProps) {
8085
return queryNameToEdit ? renderSaveDropdownMenu() : <SaveQueryButton />;
8186
}
8287

83-
interface SaveQueryDialogProps {
88+
interface SaveQueryDialogCommonProps {
8489
onSuccess?: () => void;
8590
onCancel?: () => void;
91+
onClose?: () => void;
8692
}
8793

88-
export function SaveQueryDialog({onSuccess, onCancel}: SaveQueryDialogProps) {
94+
interface SaveQueryDialogProps extends SaveQueryDialogCommonProps {
95+
open: boolean;
96+
}
97+
98+
function SaveQueryDialog({onSuccess, onCancel, onClose, open}: SaveQueryDialogProps) {
8999
const savedQueries = useSavedQueries();
90100
const dispatch = useTypedDispatch();
91-
const queryAction = useTypedSelector(selectQueryAction);
92101
const [queryName, setQueryName] = React.useState('');
93102
const [validationError, setValidationError] = React.useState<string>();
94103

@@ -106,6 +115,7 @@ export function SaveQueryDialog({onSuccess, onCancel}: SaveQueryDialogProps) {
106115
dispatch(setQueryAction('idle'));
107116
setQueryName('');
108117
setValidationError(undefined);
118+
onClose?.();
109119
};
110120

111121
const onCloseWithoutSave = () => {
@@ -125,12 +135,7 @@ export function SaveQueryDialog({onSuccess, onCancel}: SaveQueryDialogProps) {
125135
};
126136

127137
return (
128-
<Dialog
129-
open={queryAction === 'save'}
130-
hasCloseButton={false}
131-
size="s"
132-
onClose={onCloseWithoutSave}
133-
>
138+
<Dialog open={open} hasCloseButton={false} size="s" onClose={onCloseWithoutSave}>
134139
<Dialog.Header caption={i18n('action.save')} />
135140
<form
136141
onSubmit={(e) => {
@@ -175,3 +180,27 @@ export function SaveQueryDialog({onSuccess, onCancel}: SaveQueryDialogProps) {
175180
</Dialog>
176181
);
177182
}
183+
184+
export const SAVE_QUERY_DIALOG = 'save-query-dialog';
185+
186+
export const SaveQueryDialogNiceModal = NiceModal.create((props: SaveQueryDialogProps) => {
187+
const modal = NiceModal.useModal();
188+
189+
const handleClose = () => {
190+
modal.hide();
191+
modal.remove();
192+
};
193+
194+
return (
195+
<SaveQueryDialog
196+
{...props}
197+
onClose={() => {
198+
props.onClose?.();
199+
handleClose();
200+
}}
201+
open={modal.visible}
202+
/>
203+
);
204+
});
205+
206+
NiceModal.register(SAVE_QUERY_DIALOG, SaveQueryDialogNiceModal);

src/store/reducers/queryActions/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export type QueryActions = 'save' | 'idle' | 'settings';
1+
export type QueryActions = 'idle' | 'settings';
22

33
export interface QueryActionsState {
44
queryName: string | null;

src/utils/hooks/withConfirmation/useChangeInputWithConfirmation.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,36 @@ import NiceModal from '@ebay/nice-modal-react';
44

55
import {useTypedSelector} from '..';
66
import {CONFIRMATION_DIALOG} from '../../../components/ConfirmationDialog/ConfirmationDialog';
7-
import {
8-
SaveQueryButton,
9-
SaveQueryDialog,
10-
} from '../../../containers/Tenant/Query/SaveQuery/SaveQuery';
7+
import {SaveQueryButton} from '../../../containers/Tenant/Query/SaveQuery/SaveQuery';
118
import {selectUserInput} from '../../../store/reducers/executeQuery';
129

1310
import i18n from './i18n';
1411

1512
function ExtendedSaveQueryButton() {
1613
const modal = NiceModal.useModal(CONFIRMATION_DIALOG);
1714

18-
const closeModal = () => {
15+
const closeModal = React.useCallback(() => {
1916
modal.hide();
2017
modal.remove();
21-
};
22-
const handleSaveQuerySuccess = () => {
18+
}, [modal]);
19+
const handleSaveQuerySuccess = React.useCallback(() => {
2320
modal.resolve(true);
2421
closeModal();
25-
};
26-
const handleCancelQuerySave = () => {
22+
}, [modal, closeModal]);
23+
const handleCancelQuerySave = React.useCallback(() => {
2724
modal.resolve(false);
2825
closeModal();
29-
};
30-
return (
31-
<React.Fragment>
32-
<SaveQueryDialog onSuccess={handleSaveQuerySuccess} onCancel={handleCancelQuerySave} />
33-
<SaveQueryButton view="action" size="l" />
34-
</React.Fragment>
26+
}, [closeModal, modal]);
27+
28+
const dialogProps = React.useMemo(
29+
() => ({
30+
onSuccess: handleSaveQuerySuccess,
31+
onCancel: handleCancelQuerySave,
32+
}),
33+
[handleSaveQuerySuccess, handleCancelQuerySave],
3534
);
35+
36+
return <SaveQueryButton view="action" size="l" dialogProps={dialogProps} />;
3637
}
3738

3839
export async function getConfirmation(): Promise<boolean> {

0 commit comments

Comments
 (0)