From ed934a93e16ee6f69139307b4fde1cd0c38a5543 Mon Sep 17 00:00:00 2001 From: Puridach wutthihathaithamrong <76474644+puridach-w@users.noreply.github.com> Date: Fri, 26 Jan 2024 04:04:20 +0700 Subject: [PATCH] feat: Stop editor scrolling to top (#26754) Co-authored-by: Puridach Wutthihathaithamrong <> Co-authored-by: JUST.in DO IT --- superset-frontend/src/SqlLab/actions/sqlLab.js | 6 ++++++ .../AceEditorWrapper/AceEditorWrapper.test.tsx | 1 + .../SqlLab/components/AceEditorWrapper/index.tsx | 15 ++++++++++++++- .../src/SqlLab/components/SqlEditor/index.tsx | 12 +++++++++++- .../src/SqlLab/reducers/getInitialState.ts | 1 + superset-frontend/src/SqlLab/reducers/sqlLab.js | 12 ++++++++++++ superset-frontend/src/SqlLab/types.ts | 6 ++++++ 7 files changed, 51 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.js b/superset-frontend/src/SqlLab/actions/sqlLab.js index 2ee82b1552..223ca16591 100644 --- a/superset-frontend/src/SqlLab/actions/sqlLab.js +++ b/superset-frontend/src/SqlLab/actions/sqlLab.js @@ -59,6 +59,8 @@ export const QUERY_EDITOR_SET_SCHEMA = 'QUERY_EDITOR_SET_SCHEMA'; export const QUERY_EDITOR_SET_TITLE = 'QUERY_EDITOR_SET_TITLE'; export const QUERY_EDITOR_SET_AUTORUN = 'QUERY_EDITOR_SET_AUTORUN'; export const QUERY_EDITOR_SET_SQL = 'QUERY_EDITOR_SET_SQL'; +export const QUERY_EDITOR_SET_CURSOR_POSITION = + 'QUERY_EDITOR_SET_CURSOR_POSITION'; export const QUERY_EDITOR_SET_QUERY_LIMIT = 'QUERY_EDITOR_SET_QUERY_LIMIT'; export const QUERY_EDITOR_SET_TEMPLATE_PARAMS = 'QUERY_EDITOR_SET_TEMPLATE_PARAMS'; @@ -881,6 +883,10 @@ export function queryEditorSetSql(queryEditor, sql, queryId) { return { type: QUERY_EDITOR_SET_SQL, queryEditor, sql, queryId }; } +export function queryEditorSetCursorPosition(queryEditor, position) { + return { type: QUERY_EDITOR_SET_CURSOR_POSITION, queryEditor, position }; +} + export function queryEditorSetAndSaveSql(targetQueryEditor, sql, queryId) { return function (dispatch, getState) { const queryEditor = getUpToDateQuery(getState(), targetQueryEditor); diff --git a/superset-frontend/src/SqlLab/components/AceEditorWrapper/AceEditorWrapper.test.tsx b/superset-frontend/src/SqlLab/components/AceEditorWrapper/AceEditorWrapper.test.tsx index 27950a98b1..72daff7602 100644 --- a/superset-frontend/src/SqlLab/components/AceEditorWrapper/AceEditorWrapper.test.tsx +++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper/AceEditorWrapper.test.tsx @@ -51,6 +51,7 @@ const setup = (queryEditor: QueryEditor, store?: Store) => onChange={jest.fn()} onBlur={jest.fn()} autocomplete + onCursorPositionChange={jest.fn()} />, { useRedux: true, diff --git a/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx b/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx index 8529f49d4f..6069d6c69e 100644 --- a/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx +++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx @@ -25,6 +25,7 @@ import { queryEditorSetSelectedText } from 'src/SqlLab/actions/sqlLab'; import { FullSQLEditor as AceEditor } from 'src/components/AsyncAceEditor'; import type { KeyboardShortcut } from 'src/SqlLab/components/KeyboardShortcutButton'; import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; +import type { CursorPosition } from 'src/SqlLab/types'; import { useAnnotations } from './useAnnotations'; import { useKeywords } from './useKeywords'; @@ -40,6 +41,7 @@ type AceEditorWrapperProps = { onBlur: (sql: string) => void; onChange: (sql: string) => void; queryEditorId: string; + onCursorPositionChange: (position: CursorPosition) => void; height: string; hotkeys: HotKey[]; }; @@ -69,6 +71,7 @@ const AceEditorWrapper = ({ onBlur = () => {}, onChange = () => {}, queryEditorId, + onCursorPositionChange, height, hotkeys, }: AceEditorWrapperProps) => { @@ -79,10 +82,11 @@ const AceEditorWrapper = ({ 'sql', 'schema', 'templateParams', + 'cursorPosition', ]); const currentSql = queryEditor.sql ?? ''; - + const cursorPosition = queryEditor.cursorPosition ?? { row: 0, column: 0 }; const [sql, setSql] = useState(currentSql); // The editor changeSelection is called multiple times in a row, @@ -143,6 +147,15 @@ const AceEditorWrapper = ({ currentSelectionCache.current = selectedText; }); + editor.selection.on('changeCursor', () => { + const cursor = editor.getCursorPosition(); + onCursorPositionChange(cursor); + }); + + const { row, column } = cursorPosition; + editor.moveCursorToPosition({ row, column }); + editor.focus(); + editor.scrollToLine(row, true, true); }; const onChangeText = (text: string) => { diff --git a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx index e09f0c2889..0e6a4845d5 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx +++ b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx @@ -42,7 +42,11 @@ import { QueryResponse, Query, } from '@superset-ui/core'; -import type { QueryEditor, SqlLabRootState } from 'src/SqlLab/types'; +import type { + QueryEditor, + SqlLabRootState, + CursorPosition, +} from 'src/SqlLab/types'; import type { DatabaseObject } from 'src/features/databases/types'; import { debounce, throttle, isBoolean, isEmpty } from 'lodash'; import Modal from 'src/components/Modal'; @@ -63,6 +67,7 @@ import { postStopQuery, queryEditorSetAutorun, queryEditorSetSql, + queryEditorSetCursorPosition, queryEditorSetAndSaveSql, queryEditorSetTemplateParams, runQueryFromSqlEditor, @@ -757,6 +762,10 @@ const SqlEditor: React.FC = ({ ); }; + const handleCursorPositionChange = (newPosition: CursorPosition) => { + dispatch(queryEditorSetCursorPosition(queryEditor, newPosition)); + }; + const queryPane = () => { const { aceEditorHeight, southPaneHeight } = getAceEditorAndSouthPaneHeights(height, northPercent, southPercent); @@ -787,6 +796,7 @@ const SqlEditor: React.FC = ({ onBlur={onSqlChanged} onChange={onSqlChanged} queryEditorId={queryEditor.id} + onCursorPositionChange={handleCursorPositionChange} height={`${aceEditorHeight}px`} hotkeys={hotkeys} /> diff --git a/superset-frontend/src/SqlLab/reducers/getInitialState.ts b/superset-frontend/src/SqlLab/reducers/getInitialState.ts index 8d72a313b2..8f21a3ff10 100644 --- a/superset-frontend/src/SqlLab/reducers/getInitialState.ts +++ b/superset-frontend/src/SqlLab/reducers/getInitialState.ts @@ -65,6 +65,7 @@ export default function getInitialState({ queryLimit: common.conf.DEFAULT_SQLLAB_LIMIT, hideLeftBar: false, remoteId: null, + cursorPosition: { row: 0, column: 0 }, }; let unsavedQueryEditor: UnsavedQueryEditor = {}; diff --git a/superset-frontend/src/SqlLab/reducers/sqlLab.js b/superset-frontend/src/SqlLab/reducers/sqlLab.js index 59bd0558a1..1d799c559d 100644 --- a/superset-frontend/src/SqlLab/reducers/sqlLab.js +++ b/superset-frontend/src/SqlLab/reducers/sqlLab.js @@ -544,6 +544,18 @@ export default function sqlLabReducer(state = {}, action) { ), }; }, + [actions.QUERY_EDITOR_SET_CURSOR_POSITION]() { + return { + ...state, + ...alterUnsavedQueryEditorState( + state, + { + cursorPosition: action.position, + }, + action.queryEditor.id, + ), + }; + }, [actions.QUERY_EDITOR_SET_QUERY_LIMIT]() { return { ...state, diff --git a/superset-frontend/src/SqlLab/types.ts b/superset-frontend/src/SqlLab/types.ts index 6eb42718f0..ec2580f870 100644 --- a/superset-frontend/src/SqlLab/types.ts +++ b/superset-frontend/src/SqlLab/types.ts @@ -35,6 +35,11 @@ export enum QueryEditorVersion { export const LatestQueryEditorVersion = QueryEditorVersion.v1; +export interface CursorPosition { + row: number; + column: number; +} + export interface QueryEditor { version: QueryEditorVersion; id: string; @@ -56,6 +61,7 @@ export interface QueryEditor { northPercent?: number; southPercent?: number; updatedAt?: number; + cursorPosition?: CursorPosition; } export type toastState = {