From b0d8ccbf2336b52daead07a5edc9b8a569e8d16f Mon Sep 17 00:00:00 2001 From: Syngnat Date: Tue, 30 Jun 2026 20:31:44 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(definition-viewer):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AF=B9=E8=B1=A1=E5=AE=9A=E4=B9=89=E9=A1=B5?= =?UTF-8?q?=E8=A1=8C=E5=8F=B7=E9=87=8D=E5=BD=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/DefinitionViewer.tsx | 45 +++++++++++++++- frontend/src/components/MonacoEditor.tsx | 6 ++- .../MonacoEditor.typography.test.tsx | 9 ++++ frontend/src/components/TriggerViewer.tsx | 51 +++++++++++++++++-- 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/DefinitionViewer.tsx b/frontend/src/components/DefinitionViewer.tsx index 29b81367..d1d63570 100644 --- a/frontend/src/components/DefinitionViewer.tsx +++ b/frontend/src/components/DefinitionViewer.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef, useCallback } from 'react'; import Editor from './MonacoEditor'; import { Button, Spin, Alert } from 'antd'; import { EditOutlined } from '@ant-design/icons'; @@ -125,6 +125,7 @@ const DefinitionViewer: React.FC = ({ tab }) => { const [openingObjectEdit, setOpeningObjectEdit] = useState(false); const isMountedRef = useRef(true); const loadedDefinitionKeyRef = useRef(''); + const editorRef = useRef(null); const connections = useStore(state => state.connections); const theme = useStore(state => state.theme); @@ -896,6 +897,44 @@ const DefinitionViewer: React.FC = ({ tab }) => { name: normalizedObjectName, }), }; + const editorModelPath = `gonavi-definition://${encodeURIComponent(objectIdentityKey)}`; + + const refreshEditorLayout = useCallback(() => { + const editor = editorRef.current; + if (!editor) { + return; + } + + const run = () => { + editor.layout?.(); + editor.render?.(); + editor.setScrollTop?.(0); + editor.setScrollLeft?.(0); + }; + + if (typeof requestAnimationFrame === 'function') { + requestAnimationFrame(() => run()); + return; + } + + setTimeout(run, 0); + }, []); + + const handleEditorMount = useCallback((editor: any) => { + editorRef.current = editor; + refreshEditorLayout(); + }, [refreshEditorLayout]); + + useEffect(() => { + if (!displayedDefinition) { + return; + } + refreshEditorLayout(); + }, [displayedDefinition, refreshEditorLayout]); + + useEffect(() => () => { + editorRef.current = null; + }, []); const openObjectEditQuery = async () => { if (!normalizedObjectName || openingObjectEdit) return; @@ -967,15 +1006,19 @@ const DefinitionViewer: React.FC = ({ tab }) => { )}
= ({ const resolvedFontSize = gonaviTypography === 'data' ? effectiveDataTableFontSize : Math.max(10, Math.round(effectiveDataTableFontSize * 0.92)); + const effectiveEditorFontSize = Math.max( + 10, + Math.round(Number(options?.fontSize) || resolvedFontSize), + ); return { ...options, editContext: false, fontFamily: options?.fontFamily ?? monoFontFamily ?? DEFAULT_MONO_FONT_FAMILY, fontSize: options?.fontSize ?? resolvedFontSize, - lineHeight: options?.lineHeight ?? Math.max(18, Math.round(resolvedFontSize * 1.62)), + lineHeight: options?.lineHeight ?? Math.max(18, Math.round(effectiveEditorFontSize * 1.62)), }; }, [ dataTableFontSize, diff --git a/frontend/src/components/MonacoEditor.typography.test.tsx b/frontend/src/components/MonacoEditor.typography.test.tsx index b90d6250..3b7b78a6 100644 --- a/frontend/src/components/MonacoEditor.typography.test.tsx +++ b/frontend/src/components/MonacoEditor.typography.test.tsx @@ -64,6 +64,15 @@ describe('MonacoEditor typography', () => { expect(markup).toContain('"lineHeight":21'); }); + it('derives line height from the final explicit editor font size', () => { + const markup = renderToStaticMarkup( + , + ); + + expect(markup).toContain('"fontSize":18'); + expect(markup).toContain('"lineHeight":29'); + }); + it('uses data-table font size for data-oriented editors in v2', () => { storeState.fontSize = 16; storeState.appearance.dataTableFontSizeFollowGlobal = false; diff --git a/frontend/src/components/TriggerViewer.tsx b/frontend/src/components/TriggerViewer.tsx index e33a94df..e1ac9a18 100644 --- a/frontend/src/components/TriggerViewer.tsx +++ b/frontend/src/components/TriggerViewer.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef, useCallback } from 'react'; import Editor from './MonacoEditor'; import { Button, Spin, Alert } from 'antd'; import { EditOutlined } from '@ant-design/icons'; @@ -110,6 +110,7 @@ const TriggerViewer: React.FC = ({ tab }) => { const [openingObjectEdit, setOpeningObjectEdit] = useState(false); const isMountedRef = useRef(true); const loadedDefinitionKeyRef = useRef(''); + const editorRef = useRef(null); const connections = useStore(state => state.connections); const theme = useStore(state => state.theme); @@ -465,6 +466,47 @@ LIMIT 1`]; isMountedRef.current = false; }, []); + const displayedDefinition = loadedDefinitionKeyRef.current === objectIdentityKey ? triggerDefinition : ''; + const hasDefinition = String(displayedDefinition || '').trim() !== ''; + const editorModelPath = `gonavi-trigger://${encodeURIComponent(objectIdentityKey)}`; + + const refreshEditorLayout = useCallback(() => { + const editor = editorRef.current; + if (!editor) { + return; + } + + const run = () => { + editor.layout?.(); + editor.render?.(); + editor.setScrollTop?.(0); + editor.setScrollLeft?.(0); + }; + + if (typeof requestAnimationFrame === 'function') { + requestAnimationFrame(() => run()); + return; + } + + setTimeout(run, 0); + }, []); + + const handleEditorMount = useCallback((editor: any) => { + editorRef.current = editor; + refreshEditorLayout(); + }, [refreshEditorLayout]); + + useEffect(() => { + if (!displayedDefinition) { + return; + } + refreshEditorLayout(); + }, [displayedDefinition, refreshEditorLayout]); + + useEffect(() => () => { + editorRef.current = null; + }, []); + if (loading) { return (
@@ -473,9 +515,6 @@ LIMIT 1`]; ); } - const displayedDefinition = loadedDefinitionKeyRef.current === objectIdentityKey ? triggerDefinition : ''; - const hasDefinition = String(displayedDefinition || '').trim() !== ''; - if (error && !hasDefinition) { return (
@@ -537,15 +576,19 @@ LIMIT 1`]; )}