From 9da9a36cf32d48067db46237bcee73bee1e38cf7 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Wed, 24 Jun 2026 17:49:48 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(snippet):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DSQL=E7=89=87=E6=AE=B5=E5=85=A5=E5=8F=A3=E4=B8=8E?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 SQL 编辑器代码片段管理入口改为打开工具中心 SQL 片段面板 - 关闭旧独立片段弹窗入口,避免同一功能出现两个入口形态 - 限制片段管理弹窗内容区高度并固定底部操作行,避免按钮被语法参考内容挤出 --- frontend/src/App.tool-center.test.ts | 5 ++- frontend/src/App.tsx | 6 ++- .../QueryEditor.external-sql-save.test.tsx | 5 ++- .../QueryEditor.results-and-drop.test.tsx | 5 ++- .../SnippetSettingsModal.i18n.test.tsx | 38 ++++++++++++++++ .../src/components/SnippetSettingsModal.tsx | 44 ++++++++++++++++--- 6 files changed, 92 insertions(+), 11 deletions(-) diff --git a/frontend/src/App.tool-center.test.ts b/frontend/src/App.tool-center.test.ts index c027010..17e9af5 100644 --- a/frontend/src/App.tool-center.test.ts +++ b/frontend/src/App.tool-center.test.ts @@ -42,7 +42,10 @@ describe('tool center menu entries', () => { expect(appSource).toContain("key: 'snippet-settings'"); expect(appSource).toContain("title: t('app.tools.entry.snippets.title')"); expect(appSource).toContain("description: t('app.tools.entry.snippets.description')"); - expect(appSource).toContain('setIsSnippetModalOpen(true)'); + expect(appSource).toContain("handleOpenToolCenterPane('workspace', 'snippet-settings')"); + expect(appSource).toContain('gonavi:open-snippet-settings'); + expect(appSource).toContain("setIsSnippetModalOpen(false);"); + expect(appSource).not.toContain('setIsSnippetModalOpen(true)'); const snippetIndex = appSource.indexOf("key: 'snippet-settings'"); const shortcutIndex = appSource.indexOf("key: 'shortcut-settings'", snippetIndex); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index eb6377e..96f31d1 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1967,6 +1967,7 @@ function App() { setToolCenterBackGroupKey(group); setActiveToolCenterGroupKey(group); setActiveToolCenterPane({ key, group }); + setIsToolsModalOpen(true); }, []); const handleReturnToToolCenter = useCallback((closeChild?: () => void) => { const returnGroup = toolCenterBackGroupKey ?? 'config'; @@ -2472,13 +2473,14 @@ function App() { useEffect(() => { const handleOpenSnippetSettingsEvent = () => { - setIsSnippetModalOpen(true); + setIsSnippetModalOpen(false); + handleOpenToolCenterPane('workspace', 'snippet-settings'); }; window.addEventListener('gonavi:open-snippet-settings', handleOpenSnippetSettingsEvent as EventListener); return () => { window.removeEventListener('gonavi:open-snippet-settings', handleOpenSnippetSettingsEvent as EventListener); }; - }, []); + }, [handleOpenToolCenterPane]); useEffect(() => { const handleOpenTabDisplaySettingsEvent = () => { diff --git a/frontend/src/components/QueryEditor.external-sql-save.test.tsx b/frontend/src/components/QueryEditor.external-sql-save.test.tsx index aa6592d..199271b 100644 --- a/frontend/src/components/QueryEditor.external-sql-save.test.tsx +++ b/frontend/src/components/QueryEditor.external-sql-save.test.tsx @@ -7293,7 +7293,10 @@ describe('QueryEditor external SQL save', () => { expect(modalSource).toContain("defaultActiveKey={['snippet-help']}"); expect(modalSource).toContain('footer={null}'); expect(modalSource).toContain('data-sql-snippet-action-row="true"'); - expect(modalSource).toContain('body: { paddingTop: 8, paddingBottom: 24 }'); + expect(modalSource).toContain('data-sql-snippet-content-region="true"'); + expect(modalSource).toContain('data-sql-snippet-editor-scroll-region="true"'); + expect(modalSource).toContain("maxHeight: snippetModalBodyMaxHeight"); + expect(modalSource).toContain("flex: '0 0 auto'"); expect(modalSource).toContain("size=\"large\""); expect(modalSource).toContain('minWidth: 96'); expect(modalSource).toContain('syntaxHelp'); diff --git a/frontend/src/components/QueryEditor.results-and-drop.test.tsx b/frontend/src/components/QueryEditor.results-and-drop.test.tsx index 5416478..f83cb4e 100644 --- a/frontend/src/components/QueryEditor.results-and-drop.test.tsx +++ b/frontend/src/components/QueryEditor.results-and-drop.test.tsx @@ -2618,7 +2618,10 @@ describe('QueryEditor external SQL save', () => { expect(modalSource).toContain("defaultActiveKey={['snippet-help']}"); expect(modalSource).toContain('footer={null}'); expect(modalSource).toContain('data-sql-snippet-action-row="true"'); - expect(modalSource).toContain('body: { paddingTop: 8, paddingBottom: 24 }'); + expect(modalSource).toContain('data-sql-snippet-content-region="true"'); + expect(modalSource).toContain('data-sql-snippet-editor-scroll-region="true"'); + expect(modalSource).toContain("maxHeight: snippetModalBodyMaxHeight"); + expect(modalSource).toContain("flex: '0 0 auto'"); expect(modalSource).toContain("size=\"large\""); expect(modalSource).toContain('minWidth: 96'); expect(modalSource).toContain('syntaxHelp'); diff --git a/frontend/src/components/SnippetSettingsModal.i18n.test.tsx b/frontend/src/components/SnippetSettingsModal.i18n.test.tsx index 8a7b1f6..2ee7151 100644 --- a/frontend/src/components/SnippetSettingsModal.i18n.test.tsx +++ b/frontend/src/components/SnippetSettingsModal.i18n.test.tsx @@ -320,6 +320,15 @@ describe('SnippetSettingsModal i18n', () => { expect(source).not.toContain('示例:SELECT'); }); + it('keeps snippet editor content scrollable without clipping the action row', () => { + expect(source).toContain("const snippetModalBodyMaxHeight = 'calc(100vh - 128px)';"); + expect(source).toContain("maxHeight: snippetModalBodyMaxHeight"); + expect(source).toContain('data-sql-snippet-content-region="true"'); + expect(source).toContain('data-sql-snippet-editor-scroll-region="true"'); + expect(source).toContain("overflowY: 'auto'"); + expect(source).toContain("flex: '0 0 auto'"); + }); + it('keeps the shell and feedback keys available in every locale', () => { locales.forEach((locale) => { const catalog = JSON.parse(readFileSync(new URL(`../../../shared/i18n/${locale}.json`, import.meta.url), 'utf8')) as Record; @@ -364,4 +373,33 @@ describe('SnippetSettingsModal i18n', () => { expect(messageApi.warning).toHaveBeenCalledWith('Prefix is required'); }); + + it('renders a bounded content region and fixed action row for long syntax help', async () => { + const renderer = await renderModal(); + + const newButton = renderer.root.findAll((node: any) => node.type === 'button' && getText(node).includes('New Snippet'))[0]; + + await act(async () => { + newButton.props.onClick(); + }); + + const contentRegion = renderer.root.findByProps({ 'data-sql-snippet-content-region': 'true' }); + const editorScrollRegion = renderer.root.findByProps({ 'data-sql-snippet-editor-scroll-region': 'true' }); + const actionRow = renderer.root.findByProps({ 'data-sql-snippet-action-row': 'true' }); + + expect(contentRegion.props.style).toMatchObject({ + flex: '1 1 420px', + minHeight: 0, + overflow: 'hidden', + }); + expect(editorScrollRegion.props.style).toMatchObject({ + flex: 1, + minHeight: 0, + overflowY: 'auto', + }); + expect(actionRow.props.style).toMatchObject({ + flex: '0 0 auto', + justifyContent: 'flex-end', + }); + }); }); diff --git a/frontend/src/components/SnippetSettingsModal.tsx b/frontend/src/components/SnippetSettingsModal.tsx index 036ff91..1e83f1b 100644 --- a/frontend/src/components/SnippetSettingsModal.tsx +++ b/frontend/src/components/SnippetSettingsModal.tsx @@ -77,6 +77,7 @@ export default function SnippetSettingsModal({ const mutedColor = darkMode ? 'rgba(255,255,255,0.5)' : 'rgba(16,24,40,0.55)'; const selectedBg = darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.04)'; const newSnippetAction = t('snippet_settings.action.new'); + const snippetModalBodyMaxHeight = 'calc(100vh - 128px)'; const sortedSnippets = useMemo( () => [...sqlSnippets].sort((a, b) => a.prefix.localeCompare(b.prefix)), @@ -248,16 +249,34 @@ export default function SnippetSettingsModal({ styles={{ content: shellStyle, header: { background: 'transparent', borderBottom: 'none', paddingBottom: 8 }, - body: { paddingTop: 8, paddingBottom: 24 }, + body: { + paddingTop: 8, + paddingBottom: 0, + display: 'flex', + flexDirection: 'column', + maxHeight: snippetModalBodyMaxHeight, + minHeight: 0, + overflow: 'hidden', + }, }} footer={null} > -
+
{/* Left: snippet list */}
{/* Right: editor */} -
+
{showEditor ? (
@@ -379,7 +400,17 @@ export default function SnippetSettingsModal({ />
-
+
{t('snippet_settings.field.body.label')}