mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-08 22:12:29 +08:00
🐛 fix(definition-viewer): 修复对象定义页行号重影
This commit is contained in:
@@ -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<DefinitionViewerProps> = ({ tab }) => {
|
||||
const [openingObjectEdit, setOpeningObjectEdit] = useState(false);
|
||||
const isMountedRef = useRef(true);
|
||||
const loadedDefinitionKeyRef = useRef('');
|
||||
const editorRef = useRef<any>(null);
|
||||
|
||||
const connections = useStore(state => state.connections);
|
||||
const theme = useStore(state => state.theme);
|
||||
@@ -896,6 +897,44 @@ const DefinitionViewer: React.FC<DefinitionViewerProps> = ({ 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<DefinitionViewerProps> = ({ tab }) => {
|
||||
)}
|
||||
<div style={{ flex: 1, minHeight: 0 }}>
|
||||
<Editor
|
||||
path={editorModelPath}
|
||||
height="100%"
|
||||
language="sql"
|
||||
theme={darkMode ? 'transparent-dark' : 'transparent-light'}
|
||||
value={displayedDefinition}
|
||||
onMount={handleEditorMount}
|
||||
options={{
|
||||
readOnly: true,
|
||||
minimap: { enabled: false },
|
||||
fontSize: 14,
|
||||
lineHeight: 24,
|
||||
lineNumbers: 'on',
|
||||
lineNumbersMinChars: 4,
|
||||
scrollBeyondLastLine: false,
|
||||
wordWrap: 'on',
|
||||
automaticLayout: true,
|
||||
|
||||
@@ -129,13 +129,17 @@ const MonacoEditor: React.FC<MonacoEditorProps> = ({
|
||||
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,
|
||||
|
||||
@@ -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(
|
||||
<MonacoEditor options={{ fontSize: 18, minimap: { enabled: false } }} />,
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
@@ -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<TriggerViewerProps> = ({ tab }) => {
|
||||
const [openingObjectEdit, setOpeningObjectEdit] = useState(false);
|
||||
const isMountedRef = useRef(true);
|
||||
const loadedDefinitionKeyRef = useRef('');
|
||||
const editorRef = useRef<any>(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 (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
|
||||
@@ -473,9 +515,6 @@ LIMIT 1`];
|
||||
);
|
||||
}
|
||||
|
||||
const displayedDefinition = loadedDefinitionKeyRef.current === objectIdentityKey ? triggerDefinition : '';
|
||||
const hasDefinition = String(displayedDefinition || '').trim() !== '';
|
||||
|
||||
if (error && !hasDefinition) {
|
||||
return (
|
||||
<div style={{ padding: 16 }}>
|
||||
@@ -537,15 +576,19 @@ LIMIT 1`];
|
||||
)}
|
||||
<div style={{ flex: 1, minHeight: 0 }}>
|
||||
<Editor
|
||||
path={editorModelPath}
|
||||
height="100%"
|
||||
language="sql"
|
||||
theme={darkMode ? 'transparent-dark' : 'transparent-light'}
|
||||
value={displayedDefinition}
|
||||
onMount={handleEditorMount}
|
||||
options={{
|
||||
readOnly: true,
|
||||
minimap: { enabled: false },
|
||||
fontSize: 14,
|
||||
lineHeight: 24,
|
||||
lineNumbers: 'on',
|
||||
lineNumbersMinChars: 4,
|
||||
scrollBeyondLastLine: false,
|
||||
wordWrap: 'on',
|
||||
automaticLayout: true,
|
||||
|
||||
Reference in New Issue
Block a user