Skip to content

Commit c71925d

Browse files
authored
feat(ConfirmationDialog): add saving query before replace (#1629)
1 parent 5302a94 commit c71925d

File tree

6 files changed

+88
-27
lines changed

6 files changed

+88
-27
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.confirmation-dialog {
2-
&__message {
2+
&__message,
3+
&__caption {
34
white-space: pre-wrap;
45
}
56
}

src/components/ConfirmationDialog/ConfirmationDialog.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import React from 'react';
2+
13
import * as NiceModal from '@ebay/nice-modal-react';
2-
import type {ButtonView} from '@gravity-ui/uikit';
4+
import type {ButtonView, DialogFooterProps} from '@gravity-ui/uikit';
35
import {Dialog} from '@gravity-ui/uikit';
46

57
import {cn} from '../../utils/cn';
@@ -23,11 +25,11 @@ interface CommonDialogProps {
2325
onConfirm?: () => void;
2426
}
2527

26-
interface ConfirmationDialogNiceModalProps extends CommonDialogProps {
28+
interface ConfirmationDialogNiceModalProps extends CommonDialogProps, DialogFooterProps {
2729
onClose?: () => void;
2830
}
2931

30-
interface ConfirmationDialogProps extends CommonDialogProps {
32+
interface ConfirmationDialogProps extends CommonDialogProps, DialogFooterProps {
3133
onClose: () => void;
3234
open: boolean;
3335
children?: React.ReactNode;
@@ -44,6 +46,7 @@ function ConfirmationDialog({
4446
textButtonCancel,
4547
buttonApplyView = 'normal',
4648
className,
49+
renderButtons,
4750
open,
4851
}: ConfirmationDialogProps) {
4952
return (
@@ -54,7 +57,7 @@ function ConfirmationDialog({
5457
disableOutsideClick
5558
open={open}
5659
>
57-
<Dialog.Header caption={caption} />
60+
<Dialog.Header caption={<span className={block('caption')}>{caption}</span>} />
5861
<Dialog.Body>{children}</Dialog.Body>
5962
<Dialog.Footer
6063
onClickButtonApply={onConfirm}
@@ -63,6 +66,7 @@ function ConfirmationDialog({
6366
textButtonCancel={textButtonCancel ?? confirmationDialogKeyset('action_cancel')}
6467
onClickButtonCancel={onClose}
6568
loading={progress}
69+
renderButtons={renderButtons}
6670
/>
6771
</Dialog>
6872
);

src/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export const QueryEditorControls = ({
110110
</div>
111111
<div className={b('right')}>
112112
<NewSQL />
113-
<SaveQuery isSaveButtonDisabled={disabled} />
113+
<SaveQuery buttonProps={{disabled}} />
114114
</div>
115115
</div>
116116
);

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

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

3+
import type {ButtonProps} from '@gravity-ui/uikit';
34
import {Button, Dialog, DropdownMenu, TextInput} from '@gravity-ui/uikit';
45

56
import {
@@ -20,31 +21,38 @@ import './SaveQuery.scss';
2021
const b = cn('ydb-save-query');
2122

2223
interface SaveQueryProps {
23-
isSaveButtonDisabled?: boolean;
24+
buttonProps?: ButtonProps;
2425
}
2526

26-
export function SaveQuery({isSaveButtonDisabled}: SaveQueryProps) {
27+
function useSaveQueryHandler() {
2728
const dispatch = useTypedDispatch();
28-
const queryNameToEdit = useTypedSelector(selectQueryName);
29-
30-
const onSaveQueryClick = () => {
29+
const onSaveQueryClick = React.useCallback(() => {
3130
dispatch(setQueryAction('save'));
3231
dispatch(clearQueryNameToEdit());
33-
};
32+
}, [dispatch]);
33+
34+
return onSaveQueryClick;
35+
}
36+
37+
export function SaveQueryButton(props: ButtonProps) {
38+
const onSaveQueryClick = useSaveQueryHandler();
39+
return (
40+
<Button onClick={onSaveQueryClick} {...props}>
41+
{i18n('action.save')}
42+
</Button>
43+
);
44+
}
45+
46+
export function SaveQuery({buttonProps = {}}: SaveQueryProps) {
47+
const dispatch = useTypedDispatch();
48+
const queryNameToEdit = useTypedSelector(selectQueryName);
49+
const onSaveQueryClick = useSaveQueryHandler();
3450

3551
const onEditQueryClick = () => {
3652
dispatch(saveQuery(queryNameToEdit));
3753
dispatch(clearQueryNameToEdit());
3854
};
3955

40-
const renderSaveButton = () => {
41-
return (
42-
<Button onClick={onSaveQueryClick} disabled={isSaveButtonDisabled}>
43-
{i18n('action.save')}
44-
</Button>
45-
);
46-
};
47-
4856
const renderSaveDropdownMenu = () => {
4957
const items = [
5058
{
@@ -60,7 +68,7 @@ export function SaveQuery({isSaveButtonDisabled}: SaveQueryProps) {
6068
<DropdownMenu
6169
items={items}
6270
renderSwitcher={(props) => (
63-
<Button {...props} disabled={isSaveButtonDisabled}>
71+
<Button {...props} {...buttonProps}>
6472
{i18n('action.edit')}
6573
</Button>
6674
)}
@@ -69,10 +77,15 @@ export function SaveQuery({isSaveButtonDisabled}: SaveQueryProps) {
6977
);
7078
};
7179

72-
return queryNameToEdit ? renderSaveDropdownMenu() : renderSaveButton();
80+
return queryNameToEdit ? renderSaveDropdownMenu() : <SaveQueryButton />;
7381
}
7482

75-
export function SaveQueryDialog() {
83+
interface SaveQueryDialogProps {
84+
onSuccess?: () => void;
85+
onCancel?: () => void;
86+
}
87+
88+
export function SaveQueryDialog({onSuccess, onCancel}: SaveQueryDialogProps) {
7689
const savedQueries = useSavedQueries();
7790
const dispatch = useTypedDispatch();
7891
const queryAction = useTypedSelector(selectQueryAction);
@@ -95,6 +108,11 @@ export function SaveQueryDialog() {
95108
setValidationError(undefined);
96109
};
97110

111+
const onCloseWithoutSave = () => {
112+
onCancel?.();
113+
onCloseDialog();
114+
};
115+
98116
const handleQueryNameChange = (value: string) => {
99117
setQueryName(value);
100118
setValidationError(undefined);
@@ -103,14 +121,15 @@ export function SaveQueryDialog() {
103121
const onSaveClick = () => {
104122
dispatch(saveQuery(queryName));
105123
onCloseDialog();
124+
onSuccess?.();
106125
};
107126

108127
return (
109128
<Dialog
110129
open={queryAction === 'save'}
111130
hasCloseButton={false}
112131
size="s"
113-
onClose={onCloseDialog}
132+
onClose={onCloseWithoutSave}
114133
>
115134
<Dialog.Header caption={i18n('action.save')} />
116135
<form
@@ -147,7 +166,7 @@ export function SaveQueryDialog() {
147166
<Dialog.Footer
148167
textButtonApply={i18n('button-apply')}
149168
textButtonCancel={i18n('button-cancel')}
150-
onClickButtonCancel={onCloseDialog}
169+
onClickButtonCancel={onCloseWithoutSave}
151170
propsButtonApply={{
152171
type: 'submit',
153172
}}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"action_apply": "Proceed",
3-
"context_unsaved-changes-warning": "You have unsaved changes in query editor. Do you want to proceed?"
2+
"action_apply": "Don't save",
3+
"context_unsaved-changes-warning": "You have unsaved changes in query editor.\nDo you want to proceed?"
44
}

src/utils/hooks/withConfirmation/useChangeInputWithConfirmation.ts renamed to src/utils/hooks/withConfirmation/useChangeInputWithConfirmation.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,52 @@ 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';
711
import {selectUserInput} from '../../../store/reducers/executeQuery';
812

913
import i18n from './i18n';
1014

15+
function ExtendedSaveQueryButton() {
16+
const modal = NiceModal.useModal(CONFIRMATION_DIALOG);
17+
18+
const closeModal = () => {
19+
modal.hide();
20+
modal.remove();
21+
};
22+
const handleSaveQuerySuccess = () => {
23+
modal.resolve(true);
24+
closeModal();
25+
};
26+
const handleCancelQuerySave = () => {
27+
modal.resolve(false);
28+
closeModal();
29+
};
30+
return (
31+
<React.Fragment>
32+
<SaveQueryDialog onSuccess={handleSaveQuerySuccess} onCancel={handleCancelQuerySave} />
33+
<SaveQueryButton view="action" size="l" />
34+
</React.Fragment>
35+
);
36+
}
37+
1138
export async function getConfirmation(): Promise<boolean> {
1239
return await NiceModal.show(CONFIRMATION_DIALOG, {
1340
id: CONFIRMATION_DIALOG,
1441
caption: i18n('context_unsaved-changes-warning'),
1542
textButtonApply: i18n('action_apply'),
43+
propsButtonApply: {view: 'l'},
44+
renderButtons: (buttonApply: React.ReactNode, buttonCancel: React.ReactNode) => {
45+
return (
46+
<React.Fragment>
47+
{buttonCancel}
48+
<ExtendedSaveQueryButton />
49+
{buttonApply}
50+
</React.Fragment>
51+
);
52+
},
1653
});
1754
}
1855

0 commit comments

Comments
 (0)