From a2c1b4a7d8df38da1c1f68f05d9c1f1ff8570522 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Tue, 23 Jun 2026 20:18:06 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(query-editor):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=A4=96=E9=83=A8SQL=E5=BF=AB=E6=8D=B7=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 放宽活跃 QueryEditor 在文档级快捷键目标下的保存触发条件 - 修复桌面端 Ctrl/Cmd+S 事件落到 document 时未真正写盘的问题 - 保持普通查询保存行为不变,并补充外部 SQL 文件快捷保存回归测试 --- .../QueryEditor.external-sql-save.test.tsx | 41 +++++++++++++++++++ frontend/src/components/QueryEditor.tsx | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/QueryEditor.external-sql-save.test.tsx b/frontend/src/components/QueryEditor.external-sql-save.test.tsx index 1c143c3..c068483 100644 --- a/frontend/src/components/QueryEditor.external-sql-save.test.tsx +++ b/frontend/src/components/QueryEditor.external-sql-save.test.tsx @@ -4329,6 +4329,47 @@ describe('QueryEditor external SQL save', () => { expect(messageApi.success).toHaveBeenCalledWith('查询已保存!'); }); + it('allows Ctrl/Cmd+S to save external SQL files from document-level targets', async () => { + const windowListeners: Record void)[]> = {}; + vi.stubGlobal('window', { + addEventListener: vi.fn((type: string, listener: (event?: any) => void) => { + windowListeners[type] ||= []; + windowListeners[type].push(listener); + }), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + }); + + const filePath = '/Users/me/Documents/gonavi-queries/report.sql'; + editorState.hasTextFocus = false; + + await act(async () => { + create(); + }); + + editorState.value = 'select 6;'; + const isMacRuntime = /(Mac|iPhone|iPad|iPod)/i.test(`${navigator.platform || ''} ${navigator.userAgent || ''}`); + const event = { + ctrlKey: !isMacRuntime, + metaKey: isMacRuntime, + altKey: false, + shiftKey: false, + key: 's', + target: document.body, + preventDefault: vi.fn(), + stopPropagation: vi.fn(), + }; + + await act(async () => { + windowListeners.keydown?.forEach((listener) => listener(event)); + }); + + expect(event.preventDefault).toHaveBeenCalled(); + expect(event.stopPropagation).toHaveBeenCalled(); + expect(backendApp.WriteSQLFile).toHaveBeenCalledWith(filePath, 'select 6;'); + expect(messageApi.success).toHaveBeenCalledWith(expect.stringContaining('SQL 文件已保存')); + }); + it('does not create saved queries when external SQL file writes fail', async () => { let renderer!: ReactTestRenderer; const filePath = '/Users/me/Documents/gonavi-queries/report.sql'; diff --git a/frontend/src/components/QueryEditor.tsx b/frontend/src/components/QueryEditor.tsx index c619f77..5ef7a17 100644 --- a/frontend/src/components/QueryEditor.tsx +++ b/frontend/src/components/QueryEditor.tsx @@ -4132,7 +4132,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc const targetNode = resolveEventTargetNode(event.target); const editorHasFocus = !!editor?.hasTextFocus?.(); const inQueryEditor = !!(targetNode && queryEditorRootRef.current?.contains(targetNode)); - if (!editorHasFocus && !inQueryEditor) { + if (!editorHasFocus && !inQueryEditor && !isDocumentLevelShortcutTarget(targetNode)) { return; }