1
1
import { useEffect , useState } from "react" ;
2
2
import { useDiagram , useEnums , useLayout } from "../../hooks" ;
3
3
import { toDBML } from "../../utils/exportAs/dbml" ;
4
+ import { fromDBML } from "../../utils/importFrom/dbml" ;
4
5
import { Button , Tooltip } from "@douyinfe/semi-ui" ;
5
6
import { IconTemplate } from "@douyinfe/semi-icons" ;
6
7
import { useTranslation } from "react-i18next" ;
7
8
import CodeEditor from "../CodeEditor" ;
8
9
9
10
export default function DBMLEditor ( ) {
10
- const { tables : currentTables , relationships } = useDiagram ( ) ;
11
11
const diagram = useDiagram ( ) ;
12
- const { enums } = useEnums ( ) ;
12
+ const {
13
+ tables : currentTables ,
14
+ relationships,
15
+ setTables,
16
+ setRelationships,
17
+ database,
18
+ } = diagram ;
19
+ const { enums, setEnums } = useEnums ( ) ;
13
20
const [ value , setValue ] = useState ( ( ) => toDBML ( { ...diagram , enums } ) ) ;
14
21
const { setLayout } = useLayout ( ) ;
22
+ const { setExternalIssues } = diagram ;
15
23
const { t } = useTranslation ( ) ;
16
24
17
25
const toggleDBMLEditor = ( ) => {
18
26
setLayout ( ( prev ) => ( { ...prev , dbmlEditor : ! prev . dbmlEditor } ) ) ;
19
27
} ;
20
28
21
29
useEffect ( ( ) => {
22
- setValue ( toDBML ( { tables : currentTables , enums, relationships } ) ) ;
23
- } , [ currentTables , enums , relationships ] ) ;
30
+ const normalized = toDBML ( {
31
+ tables : currentTables ,
32
+ enums,
33
+ relationships,
34
+ database,
35
+ } ) ;
36
+ setValue ( normalized ) ;
37
+ } , [ currentTables , enums , relationships , database ] ) ;
38
+
39
+ useEffect ( ( ) => {
40
+ const currentDbml = toDBML ( {
41
+ tables : currentTables ,
42
+ enums,
43
+ relationships,
44
+ database,
45
+ } ) ;
46
+
47
+ if ( value === currentDbml ) return ;
48
+
49
+ const handle = setTimeout ( ( ) => {
50
+ try {
51
+ const parsed = fromDBML ( value ) ;
52
+ // Preserve coordinates when table names match existing ones
53
+ const nameToExisting = new Map (
54
+ currentTables . map ( ( t ) => [ t . name , { x : t . x , y : t . y } ] ) ,
55
+ ) ;
56
+ parsed . tables = parsed . tables . map ( ( t ) => {
57
+ const coords = nameToExisting . get ( t . name ) ;
58
+ return coords ? { ...t , ...coords } : t ;
59
+ } ) ;
60
+ setTables ( parsed . tables ) ;
61
+ setRelationships ( parsed . relationships ) ;
62
+ setEnums ( parsed . enums ) ;
63
+ // Clear any previous external issues on success
64
+ setExternalIssues ( [ ] ) ;
65
+ } catch ( err ) {
66
+ const message = err ?. message || String ( err ) ;
67
+ // Put parse error into Issues panel instead of toast spam
68
+ setExternalIssues ( [ message ] ) ;
69
+ setEditorMarkersFromError ( message ) ;
70
+ }
71
+ } , 700 ) ;
72
+
73
+ return ( ) => clearTimeout ( handle ) ;
74
+ } , [
75
+ value ,
76
+ currentTables ,
77
+ enums ,
78
+ relationships ,
79
+ database ,
80
+ setTables ,
81
+ setRelationships ,
82
+ setEnums ,
83
+ setExternalIssues ,
84
+ ] ) ;
85
+
86
+ // Translate DBML parse error message to Monaco markers
87
+ const [ markers , setMarkers ] = useState ( [ ] ) ;
88
+ const setEditorMarkersFromError = ( message ) => {
89
+ // Try to extract line/column like: "line X, column Y" or "(X:Y)"
90
+ const lineColMatch =
91
+ / l i n e \s + ( \d + ) \s * , \s * c o l u m n \s * ( \d + ) / i. exec ( message ) ||
92
+ / \( ( \d + ) \s * [: | , ] \s * ( \d + ) \) / . exec ( message ) ;
93
+
94
+ const lineNumber = lineColMatch ? parseInt ( lineColMatch [ 1 ] , 10 ) : 1 ;
95
+ const column = lineColMatch ? parseInt ( lineColMatch [ 2 ] , 10 ) : 1 ;
96
+
97
+ setMarkers ( [
98
+ {
99
+ startLineNumber : lineNumber ,
100
+ startColumn : column ,
101
+ endLineNumber : lineNumber ,
102
+ endColumn : column + 1 ,
103
+ message,
104
+ } ,
105
+ ] ) ;
106
+ } ;
24
107
25
108
return (
26
109
< CodeEditor
@@ -29,8 +112,9 @@ export default function DBMLEditor() {
29
112
language = "dbml"
30
113
onChange = { setValue }
31
114
height = "100%"
115
+ markers = { markers }
32
116
options = { {
33
- readOnly : true ,
117
+ readOnly : false ,
34
118
minimap : { enabled : false } ,
35
119
} }
36
120
extraControls = {
0 commit comments