From df87e50b334c53dbf536f6d404c7fa6509b048b8 Mon Sep 17 00:00:00 2001 From: AutumnNazi <104422820+AutumnNazi@users.noreply.github.com> Date: Mon, 27 Jul 2026 21:10:04 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(query-editor):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20SQL=20=E7=BE=8E=E5=8C=96=E5=90=8E=E6=A8=AA=E5=90=91?= =?UTF-8?q?=E8=A7=86=E5=8F=A3=E5=81=8F=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SQL 格式化完成后重置 Monaco 横向滚动位置 - 保留格式化内容、选区、纵向滚动与撤销行为 - 补充超长单行 SQL 非自动换行场景回归测试 --- .../QueryEditor.external-sql-save.test.tsx | 28 +++++++++++++++++++ frontend/src/components/QueryEditor.tsx | 1 + 2 files changed, 29 insertions(+) diff --git a/frontend/src/components/QueryEditor.external-sql-save.test.tsx b/frontend/src/components/QueryEditor.external-sql-save.test.tsx index 4b7f545d..7883eebf 100644 --- a/frontend/src/components/QueryEditor.external-sql-save.test.tsx +++ b/frontend/src/components/QueryEditor.external-sql-save.test.tsx @@ -209,6 +209,7 @@ const editorState = vi.hoisted(() => { }, position: { lineNumber: 1, column: 1 }, selection: null as any, + scrollLeft: 0, providers: [] as any[], providerLanguages: [] as string[], hoverProviders: [] as any[], @@ -292,6 +293,10 @@ const editorState = vi.hoisted(() => { setSelections: vi.fn((selections: any[]) => { state.selection = Array.isArray(selections) ? selections[0] ?? null : null; }), + getScrollLeft: vi.fn(() => state.scrollLeft), + setScrollLeft: vi.fn((scrollLeft: number) => { + state.scrollLeft = scrollLeft; + }), executeEdits: vi.fn((_source: string, edits: any[]) => { edits.forEach((edit) => { const start = offsetAt({ lineNumber: edit.range.startLineNumber, column: edit.range.startColumn }); @@ -897,6 +902,7 @@ describe('QueryEditor external SQL save', () => { editorState.value = ''; editorState.position = { lineNumber: 1, column: 1 }; editorState.selection = null; + editorState.scrollLeft = 0; monacoEditorMockState.latestProps = null; editorState.domNode.style.cursor = ''; editorState.providers = []; @@ -919,6 +925,8 @@ describe('QueryEditor external SQL save', () => { editorState.editor.getModel().getValueLength.mockClear(); editorState.editor.setValue.mockClear(); editorState.editor.executeEdits.mockClear(); + editorState.editor.getScrollLeft.mockClear(); + editorState.editor.setScrollLeft.mockClear(); editorState.editor.deltaDecorations.mockClear(); editorState.editor.updateOptions.mockClear(); editorState.editor.pushUndoStop.mockClear(); @@ -4427,6 +4435,26 @@ describe('QueryEditor external SQL save', () => { }); }); + it('resets stale horizontal scroll after formatting a long single-line SQL statement', async () => { + let renderer!: ReactTestRenderer; + const longSql = `select ${Array.from({ length: 80 }, (_, index) => `column_${index + 1}`).join(', ')} from users where id=1`; + + await act(async () => { + renderer = create(); + }); + + editorState.scrollLeft = 2400; + + const formatButton = findButton(renderer, '美化'); + await act(async () => { + await formatButton.props.onClick(); + }); + + expect(editorState.editor.executeEdits).toHaveBeenCalled(); + expect(editorState.editor.setScrollLeft).toHaveBeenCalledWith(0); + expect(editorState.scrollLeft).toBe(0); + }); + it('formats only the selected SQL when a non-empty selection exists', async () => { let renderer!: ReactTestRenderer; const originalSql = 'select 1; select * from users where id=1'; diff --git a/frontend/src/components/QueryEditor.tsx b/frontend/src/components/QueryEditor.tsx index fc8e71b5..6f4d18a5 100644 --- a/frontend/src/components/QueryEditor.tsx +++ b/frontend/src/components/QueryEditor.tsx @@ -6178,6 +6178,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc const nextValue = editor.getValue?.(); applyQueryState(typeof nextValue === 'string' ? nextValue : (formatSelection ? currentValue : formatted)); refreshObjectDecorations(); + editor.setScrollLeft?.(0); return; } if (formatSelection) {