Skip to content

Commit 4db34be

Browse files
authored
fix(QueryEditor): dont render Results every time editor input changes (#1879)
1 parent ba22a39 commit 4db34be

File tree

3 files changed

+240
-197
lines changed

3 files changed

+240
-197
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
import React from 'react';
22

3-
import NiceModal from '@ebay/nice-modal-react';
43
import {isEqual} from 'lodash';
5-
import throttle from 'lodash/throttle';
6-
import type Monaco from 'monaco-editor';
74
import {v4 as uuidv4} from 'uuid';
85

9-
import {MonacoEditor} from '../../../../components/MonacoEditor/MonacoEditor';
106
import SplitPane from '../../../../components/SplitPane';
117
import {useTracingLevelOptionAvailable} from '../../../../store/reducers/capabilities/hooks';
128
import {
13-
goToNextQuery,
14-
goToPreviousQuery,
159
queryApi,
1610
saveQueryToHistory,
1711
selectQueriesHistory,
1812
selectQueriesHistoryCurrentIndex,
1913
selectResult,
2014
selectTenantPath,
21-
selectUserInput,
2215
setTenantPath,
2316
} from '../../../../store/reducers/query/query';
2417
import type {QueryResult} from '../../../../store/reducers/query/types';
@@ -41,8 +34,6 @@ import {
4134
} from '../../../../utils/hooks';
4235
import {useChangedQuerySettings} from '../../../../utils/hooks/useChangedQuerySettings';
4336
import {useLastQueryExecutionSettings} from '../../../../utils/hooks/useLastQueryExecutionSettings';
44-
import {YQL_LANGUAGE_ID} from '../../../../utils/monaco/constats';
45-
import {useUpdateErrorsHighlighting} from '../../../../utils/monaco/highlightErrors';
4637
import {QUERY_ACTIONS} from '../../../../utils/query';
4738
import type {InitialPaneState} from '../../utils/paneVisibilityToggleHelpers';
4839
import {
@@ -53,16 +44,11 @@ import {Preview} from '../Preview/Preview';
5344
import {QueryEditorControls} from '../QueryEditorControls/QueryEditorControls';
5445
import {QueryResultViewer} from '../QueryResult/QueryResultViewer';
5546
import {QuerySettingsDialog} from '../QuerySettingsDialog/QuerySettingsDialog';
56-
import {SAVE_QUERY_DIALOG} from '../SaveQuery/SaveQuery';
57-
import i18n from '../i18n';
5847

59-
import {useEditorOptions} from './helpers';
60-
import {getKeyBindings} from './keybindings';
48+
import {YqlEditor} from './YqlEditor';
6149

6250
import './QueryEditor.scss';
6351

64-
const CONTEXT_MENU_GROUP_ID = 'navigation';
65-
6652
const b = cn('query-editor');
6753

6854
const initialTenantCommonInfoState = {
@@ -80,18 +66,14 @@ interface QueryEditorProps {
8066
}
8167

8268
export default function QueryEditor(props: QueryEditorProps) {
83-
const editorOptions = useEditorOptions();
8469
const dispatch = useTypedDispatch();
8570
const {tenantName, path, type, theme, changeUserInput} = props;
8671
const savedPath = useTypedSelector(selectTenantPath);
8772
const result = useTypedSelector(selectResult);
8873
const historyQueries = useTypedSelector(selectQueriesHistory);
8974
const historyCurrentIndex = useTypedSelector(selectQueriesHistoryCurrentIndex);
90-
const input = useTypedSelector(selectUserInput);
9175
const showPreview = useTypedSelector(selectShowPreview);
9276

93-
const updateErrorsHighlighting = useUpdateErrorsHighlighting();
94-
9577
const isResultLoaded = Boolean(result);
9678

9779
const [querySettings] = useQueryExecutionSettings();
@@ -130,18 +112,9 @@ export default function QueryEditor(props: QueryEditorProps) {
130112
}
131113
}, [showPreview, isResultLoaded]);
132114

133-
const getLastQueryText = useEventHandler(() => {
134-
if (!historyQueries || historyQueries.length === 0) {
135-
return '';
136-
}
137-
return historyQueries[historyQueries.length - 1].queryText;
138-
});
139-
140-
const handleSendExecuteClick = useEventHandler((text?: string) => {
141-
const query = text ?? input;
142-
115+
const handleSendExecuteClick = useEventHandler((text: string, partial?: boolean) => {
143116
setLastUsedQueryAction(QUERY_ACTIONS.execute);
144-
setLastExecutedQueryText(query);
117+
setLastExecutedQueryText(text);
145118
if (!isEqual(lastQueryExecutionSettings, querySettings)) {
146119
resetBanner();
147120
setLastQueryExecutionSettings(querySettings);
@@ -150,7 +123,7 @@ export default function QueryEditor(props: QueryEditorProps) {
150123

151124
sendQuery({
152125
actionType: 'execute',
153-
query,
126+
query: text,
154127
database: tenantName,
155128
querySettings,
156129
enableTracingLevel,
@@ -160,9 +133,9 @@ export default function QueryEditor(props: QueryEditorProps) {
160133
dispatch(setShowPreview(false));
161134

162135
// Don't save partial queries in history
163-
if (!text) {
164-
if (query !== historyQueries[historyCurrentIndex]?.queryText) {
165-
dispatch(saveQueryToHistory({queryText: input, queryId}));
136+
if (!partial) {
137+
if (text !== historyQueries[historyCurrentIndex]?.queryText) {
138+
dispatch(saveQueryToHistory({queryText: text, queryId}));
166139
}
167140
}
168141
dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
@@ -172,9 +145,9 @@ export default function QueryEditor(props: QueryEditorProps) {
172145
dispatch(setQueryAction('settings'));
173146
};
174147

175-
const handleGetExplainQueryClick = useEventHandler(() => {
148+
const handleGetExplainQueryClick = useEventHandler((text: string) => {
176149
setLastUsedQueryAction(QUERY_ACTIONS.explain);
177-
setLastExecutedQueryText(input);
150+
setLastExecutedQueryText(text);
178151
if (!isEqual(lastQueryExecutionSettings, querySettings)) {
179152
resetBanner();
180153
setLastQueryExecutionSettings(querySettings);
@@ -184,7 +157,7 @@ export default function QueryEditor(props: QueryEditorProps) {
184157

185158
sendQuery({
186159
actionType: 'explain',
187-
query: input,
160+
query: text,
188161
database: tenantName,
189162
querySettings,
190163
enableTracingLevel,
@@ -196,113 +169,6 @@ export default function QueryEditor(props: QueryEditorProps) {
196169
dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
197170
});
198171

199-
const handleSendQuery = useEventHandler(() => {
200-
if (lastUsedQueryAction === QUERY_ACTIONS.explain) {
201-
handleGetExplainQueryClick();
202-
} else {
203-
handleSendExecuteClick();
204-
}
205-
});
206-
207-
const editorWillUnmount = () => {
208-
window.ydbEditor = undefined;
209-
};
210-
211-
const editorDidMount = (editor: Monaco.editor.IStandaloneCodeEditor, monaco: typeof Monaco) => {
212-
window.ydbEditor = editor;
213-
const keybindings = getKeyBindings(monaco);
214-
monaco.editor.registerCommand('insertSnippetToEditor', (_asessor, input: string) => {
215-
//suggestController is not properly typed yet in monaco-editor package
216-
const contribution = editor.getContribution<any>('snippetController2');
217-
if (contribution) {
218-
editor.focus();
219-
editor.setValue('');
220-
contribution.insert(input);
221-
}
222-
});
223-
initResizeHandler(editor);
224-
initUserPrompt(editor, getLastQueryText);
225-
editor.focus();
226-
editor.addAction({
227-
id: 'sendQuery',
228-
label: i18n('action.send-query'),
229-
keybindings: [keybindings.sendQuery],
230-
// A precondition for this action.
231-
precondition: undefined,
232-
// A rule to evaluate on top of the precondition in order to dispatch the keybindings.
233-
keybindingContext: undefined,
234-
contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
235-
contextMenuOrder: 1,
236-
// Method that will be executed when the action is triggered.
237-
// @param editor The editor instance is passed in as a convenience
238-
run: () => handleSendQuery(),
239-
});
240-
241-
const canSendSelectedText = editor.createContextKey<boolean>('canSendSelectedText', false);
242-
editor.onDidChangeCursorSelection(({selection, secondarySelections}) => {
243-
const notEmpty =
244-
selection.selectionStartLineNumber !== selection.positionLineNumber ||
245-
selection.selectionStartColumn !== selection.positionColumn;
246-
const hasMultipleSelections = secondarySelections.length > 0;
247-
canSendSelectedText.set(notEmpty && !hasMultipleSelections);
248-
});
249-
editor.addAction({
250-
id: 'sendSelectedQuery',
251-
label: i18n('action.send-selected-query'),
252-
keybindings: [keybindings.sendSelectedQuery],
253-
precondition: 'canSendSelectedText',
254-
contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
255-
contextMenuOrder: 1,
256-
run: (e) => {
257-
const selection = e.getSelection();
258-
const model = e.getModel();
259-
if (selection && model) {
260-
const text = model.getValueInRange({
261-
startLineNumber: selection.getSelectionStart().lineNumber,
262-
startColumn: selection.getSelectionStart().column,
263-
endLineNumber: selection.getPosition().lineNumber,
264-
endColumn: selection.getPosition().column,
265-
});
266-
handleSendExecuteClick(text);
267-
}
268-
},
269-
});
270-
271-
editor.addAction({
272-
id: 'previous-query',
273-
label: i18n('action.previous-query'),
274-
keybindings: [keybindings.selectPreviousQuery],
275-
contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
276-
contextMenuOrder: 2,
277-
run: () => {
278-
dispatch(goToPreviousQuery());
279-
},
280-
});
281-
editor.addAction({
282-
id: 'next-query',
283-
label: i18n('action.next-query'),
284-
keybindings: [keybindings.selectNextQuery],
285-
contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
286-
contextMenuOrder: 3,
287-
run: () => {
288-
dispatch(goToNextQuery());
289-
},
290-
});
291-
editor.addAction({
292-
id: 'save-query',
293-
label: i18n('action.save-query'),
294-
keybindings: [keybindings.saveQuery],
295-
run: () => {
296-
NiceModal.show(SAVE_QUERY_DIALOG);
297-
},
298-
});
299-
};
300-
301-
const onChange = (newValue: string) => {
302-
updateErrorsHighlighting();
303-
changeUserInput({input: newValue});
304-
};
305-
306172
const onCollapseResultHandler = () => {
307173
dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerCollapse);
308174
};
@@ -321,7 +187,6 @@ export default function QueryEditor(props: QueryEditorProps) {
321187
onSettingsButtonClick={handleSettingsClick}
322188
isLoading={Boolean(result?.isLoading)}
323189
handleGetExplainQueryClick={handleGetExplainQueryClick}
324-
disabled={!input}
325190
highlightedAction={lastUsedQueryAction}
326191
/>
327192
);
@@ -345,14 +210,11 @@ export default function QueryEditor(props: QueryEditorProps) {
345210
>
346211
<div className={b('monaco-wrapper')}>
347212
<div className={b('monaco')}>
348-
<MonacoEditor
349-
language={YQL_LANGUAGE_ID}
350-
value={input}
351-
options={editorOptions}
352-
onChange={onChange}
353-
editorDidMount={editorDidMount}
354-
theme={`vs-${theme}`}
355-
editorWillUnmount={editorWillUnmount}
213+
<YqlEditor
214+
changeUserInput={changeUserInput}
215+
theme={theme}
216+
handleSendExecuteClick={handleSendExecuteClick}
217+
handleGetExplainQueryClick={handleGetExplainQueryClick}
356218
/>
357219
</div>
358220
</div>
@@ -424,40 +286,3 @@ function Result({
424286

425287
return null;
426288
}
427-
428-
function initResizeHandler(editor: Monaco.editor.IStandaloneCodeEditor) {
429-
const layoutEditor = throttle(() => {
430-
editor.layout();
431-
}, 100);
432-
433-
editor.layout();
434-
435-
window.addEventListener('resize', layoutEditor);
436-
editor.onDidDispose(() => {
437-
window.removeEventListener('resize', layoutEditor);
438-
});
439-
}
440-
441-
function initUserPrompt(editor: Monaco.editor.IStandaloneCodeEditor, getInitialText: () => string) {
442-
setUserPrompt(editor.getValue(), getInitialText());
443-
editor.onDidChangeModelContent(() => {
444-
setUserPrompt(editor.getValue(), getInitialText());
445-
});
446-
editor.onDidDispose(() => {
447-
window.onbeforeunload = null;
448-
});
449-
}
450-
451-
function setUserPrompt(text: string, initialText: string) {
452-
const hasUnsavedInput = text ? text !== initialText : false;
453-
454-
if (hasUnsavedInput) {
455-
window.onbeforeunload = (e) => {
456-
e.preventDefault();
457-
// Chrome requires returnValue to be set
458-
e.returnValue = '';
459-
};
460-
} else {
461-
window.onbeforeunload = null;
462-
}
463-
}

0 commit comments

Comments
 (0)