mirror of
				https://github.com/chartdb/chartdb.git
				synced 2025-11-03 21:43:23 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			main
			...
			jf/fix_fk_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1377bd524b | 
							
								
								
									
										2
									
								
								.github/workflows/cla.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/cla.yaml
									
									
									
									
										vendored
									
									
								
							@@ -7,7 +7,7 @@ on:
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  actions: write
 | 
			
		||||
  contents: read
 | 
			
		||||
  contents: write # this can be 'read' if the signatures are in remote repository
 | 
			
		||||
  pull-requests: write
 | 
			
		||||
  statuses: write
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										180
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,185 +1,5 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
 | 
			
		||||
## [1.17.0](https://github.com/chartdb/chartdb/compare/v1.16.0...v1.17.0) (2025-10-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* create relationships on canvas modal ([#946](https://github.com/chartdb/chartdb/issues/946)) ([34475ad](https://github.com/chartdb/chartdb/commit/34475add32f11323589ef092ccf2a8e9152ff272))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* add auto-increment field detection in smart-query import ([#935](https://github.com/chartdb/chartdb/issues/935)) ([57b3b87](https://github.com/chartdb/chartdb/commit/57b3b8777fd0a445abf0ba6603faab612d469d5c))
 | 
			
		||||
* add open table in editor from canvas edit ([#952](https://github.com/chartdb/chartdb/issues/952)) ([7d811de](https://github.com/chartdb/chartdb/commit/7d811de097eb11e51012772fa6bf586fd0b16c62))
 | 
			
		||||
* add rels export dbml ([#937](https://github.com/chartdb/chartdb/issues/937)) ([c3c646b](https://github.com/chartdb/chartdb/commit/c3c646bf7cbb1328f4b2eb85c9a7e929f0fcd3b9))
 | 
			
		||||
* add support for arrays ([#949](https://github.com/chartdb/chartdb/issues/949)) ([49328d8](https://github.com/chartdb/chartdb/commit/49328d8fbd7786f6c0c04cd5605d43a24cbf10ea))
 | 
			
		||||
* add support for parsing default values in DBML ([#948](https://github.com/chartdb/chartdb/issues/948)) ([459698b](https://github.com/chartdb/chartdb/commit/459698b5d0a1ff23a3719c2e55e4ab2e2384c4fe))
 | 
			
		||||
* add timestampz and int as datatypes to postgres ([#940](https://github.com/chartdb/chartdb/issues/940)) ([b15bc94](https://github.com/chartdb/chartdb/commit/b15bc945acb96d7cb3832b3b1b607dfcaef9e5ca))
 | 
			
		||||
* auto-enter edit mode when creating new tables from canvas ([#943](https://github.com/chartdb/chartdb/issues/943)) ([bcd8aa9](https://github.com/chartdb/chartdb/commit/bcd8aa9378aa563f40a2b6802cc503be4c882356))
 | 
			
		||||
* dbml diff fields types preview ([#934](https://github.com/chartdb/chartdb/issues/934)) ([bb03309](https://github.com/chartdb/chartdb/commit/bb033091b1f64b888822be1423a80f16f5314f6b))
 | 
			
		||||
* exit table edit on area click ([#945](https://github.com/chartdb/chartdb/issues/945)) ([38fedce](https://github.com/chartdb/chartdb/commit/38fedcec0c10ea2b3f0b7fc92ca1f5ac9e540389))
 | 
			
		||||
* import array fields ([#961](https://github.com/chartdb/chartdb/issues/961)) ([91e713c](https://github.com/chartdb/chartdb/commit/91e713c30a44f1ba7a767ca7816079610136fcb8))
 | 
			
		||||
* manipulate schema directly from the canvas ([#947](https://github.com/chartdb/chartdb/issues/947)) ([7ad0e77](https://github.com/chartdb/chartdb/commit/7ad0e7712de975a23b2a337dc0a4a7fb4b122bd1))
 | 
			
		||||
* preserve multi-word types in DBML export/import ([#956](https://github.com/chartdb/chartdb/issues/956)) ([9ed27cf](https://github.com/chartdb/chartdb/commit/9ed27cf30cca1312713e80e525138f0c27154936))
 | 
			
		||||
* prevent text input glitch when editing table field names ([#944](https://github.com/chartdb/chartdb/issues/944)) ([498655e](https://github.com/chartdb/chartdb/commit/498655e7b77e57eaf641ba86263ce1ef60b93e16))
 | 
			
		||||
* resolve canvas filter tree state issues ([#953](https://github.com/chartdb/chartdb/issues/953)) ([ccb29e0](https://github.com/chartdb/chartdb/commit/ccb29e0a574dfa4cfdf0ebf242a4c4aaa48cc37b))
 | 
			
		||||
* resolve dbml increment & nullable attributes issue ([#954](https://github.com/chartdb/chartdb/issues/954)) ([2c4b344](https://github.com/chartdb/chartdb/commit/2c4b344efb24041e7f607fc6124e109b69aaa457))
 | 
			
		||||
* show SQL Script option conditionally for databases without DDL support ([#960](https://github.com/chartdb/chartdb/issues/960)) ([acf6d4b](https://github.com/chartdb/chartdb/commit/acf6d4b3654d8868b8a8ebf717c608d9749b71da))
 | 
			
		||||
* use flag for custom types ([#951](https://github.com/chartdb/chartdb/issues/951)) ([62dec48](https://github.com/chartdb/chartdb/commit/62dec4857211b705a8039691da1772263ea986fe))
 | 
			
		||||
 | 
			
		||||
## [1.16.0](https://github.com/chartdb/chartdb/compare/v1.15.1...v1.16.0) (2025-09-24)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* add area context menu and UI improvements ([#918](https://github.com/chartdb/chartdb/issues/918)) ([d09379e](https://github.com/chartdb/chartdb/commit/d09379e8be0fa3c83ca77ff62ae815fe4db9869b))
 | 
			
		||||
* add quick table mode on canvas ([#915](https://github.com/chartdb/chartdb/issues/915)) ([8954d89](https://github.com/chartdb/chartdb/commit/8954d893bbfee45bb311380115fb14ebbf3a3133))
 | 
			
		||||
* add zoom navigation buttons to canvas filter for tables and areas ([#903](https://github.com/chartdb/chartdb/issues/903)) ([a0fb1ed](https://github.com/chartdb/chartdb/commit/a0fb1ed08ba18b66354fa3498d610097a83d4afc))
 | 
			
		||||
* **import-db:** add DBML syntax to import database dialog ([#768](https://github.com/chartdb/chartdb/issues/768)) ([af3638d](https://github.com/chartdb/chartdb/commit/af3638da7a9b70f281ceaddbc2f712a713d90cda))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* add areas width and height + table width to diff check ([#931](https://github.com/chartdb/chartdb/issues/931)) ([98f6edd](https://github.com/chartdb/chartdb/commit/98f6edd5c8a8e9130e892b2d841744e0cf63a7bf))
 | 
			
		||||
* add diff x,y ([#928](https://github.com/chartdb/chartdb/issues/928)) ([e4c4a3b](https://github.com/chartdb/chartdb/commit/e4c4a3b35484d9ece955a5aec577603dde73d634))
 | 
			
		||||
* add support for ALTER TABLE ADD COLUMN in PostgreSQL importer ([#892](https://github.com/chartdb/chartdb/issues/892)) ([ec6e46f](https://github.com/chartdb/chartdb/commit/ec6e46fe81ea1806c179c50a4c5779d8596008aa))
 | 
			
		||||
* add tests for diff ([#930](https://github.com/chartdb/chartdb/issues/930)) ([47a7a73](https://github.com/chartdb/chartdb/commit/47a7a73a137b87dfa6e67aff5f939cf64ccf4601))
 | 
			
		||||
* dbml edit mode glitch ([#925](https://github.com/chartdb/chartdb/issues/925)) ([93d72a8](https://github.com/chartdb/chartdb/commit/93d72a896bab9aa79d8ea2f876126887e432214c))
 | 
			
		||||
* dbml export default time bug ([#922](https://github.com/chartdb/chartdb/issues/922)) ([bc82f9d](https://github.com/chartdb/chartdb/commit/bc82f9d6a8fe4de2f7e0fc465e0a20c5dbf8f41d))
 | 
			
		||||
* dbml export renaming fields bug ([#921](https://github.com/chartdb/chartdb/issues/921)) ([26dc299](https://github.com/chartdb/chartdb/commit/26dc299cd28e9890d191c13f84a15ac38ae48b11))
 | 
			
		||||
* **dbml:** export array fields without quotes ([#911](https://github.com/chartdb/chartdb/issues/911)) ([5e81c18](https://github.com/chartdb/chartdb/commit/5e81c1848aaa911990e1e881d62525f5254d6d34))
 | 
			
		||||
* diff logic ([#927](https://github.com/chartdb/chartdb/issues/927)) ([1b8d51b](https://github.com/chartdb/chartdb/commit/1b8d51b73c4ed4b7c5929adcb17a44927c7defca))
 | 
			
		||||
* export dbml issues after upgrade version ([#883](https://github.com/chartdb/chartdb/issues/883)) ([07937a2](https://github.com/chartdb/chartdb/commit/07937a2f51708b1c10b45c2bd1f9a9acf5c3f708))
 | 
			
		||||
* export sql + import metadata lib ([#902](https://github.com/chartdb/chartdb/issues/902)) ([ffddcdc](https://github.com/chartdb/chartdb/commit/ffddcdcc987bacb0e0d7e8dea27d08d3a8c5a8c8))
 | 
			
		||||
* handle bidirectional relationships in DBML export ([#924](https://github.com/chartdb/chartdb/issues/924)) ([9991077](https://github.com/chartdb/chartdb/commit/99910779789a9c6ef113d06bc3de31e35b9b04d1))
 | 
			
		||||
* import dbml set pk field unique ([#920](https://github.com/chartdb/chartdb/issues/920)) ([d6ba4a4](https://github.com/chartdb/chartdb/commit/d6ba4a40749d85d2703f120600df4345dab3c561))
 | 
			
		||||
* improve SQL default value parsing for PostgreSQL, MySQL, and SQL Server with proper type handling and casting support ([#900](https://github.com/chartdb/chartdb/issues/900)) ([fe9ef27](https://github.com/chartdb/chartdb/commit/fe9ef275b8619dcfd7e57541a62a6237a16d29a8))
 | 
			
		||||
* move area utils ([#932](https://github.com/chartdb/chartdb/issues/932)) ([2dc1a6f](https://github.com/chartdb/chartdb/commit/2dc1a6fc7519e0a455b0e1306601195deb156c96))
 | 
			
		||||
* move auto arrange to toolbar ([#904](https://github.com/chartdb/chartdb/issues/904)) ([b016a70](https://github.com/chartdb/chartdb/commit/b016a70691bc22af5720b4de683e8c9353994fcc))
 | 
			
		||||
* remove general db creation ([#901](https://github.com/chartdb/chartdb/issues/901)) ([df89f0b](https://github.com/chartdb/chartdb/commit/df89f0b6b9ba3fcc8b05bae4f60c0dc4ad1d2215))
 | 
			
		||||
* remove many to many rel option ([#933](https://github.com/chartdb/chartdb/issues/933)) ([c567c0a](https://github.com/chartdb/chartdb/commit/c567c0a5f39157b2c430e92192b6750304d7a834))
 | 
			
		||||
* reset increment and default when change field ([#896](https://github.com/chartdb/chartdb/issues/896)) ([e5e1d59](https://github.com/chartdb/chartdb/commit/e5e1d5932762422ea63acfd6cf9fe4f03aa822f7))
 | 
			
		||||
* **sql-import:** handle SQL Server DDL with multiple tables, inline foreign keys, and case-insensitive field matching ([#897](https://github.com/chartdb/chartdb/issues/897)) ([2a64dee](https://github.com/chartdb/chartdb/commit/2a64deebb87a11ee3892024c3273d682bb86f7ef))
 | 
			
		||||
* **sql-import:** support ALTER TABLE ALTER COLUMN TYPE in PostgreSQL importer ([#895](https://github.com/chartdb/chartdb/issues/895)) ([aa29061](https://github.com/chartdb/chartdb/commit/aa290615caf806d7d0374c848d50b4636fde7e96))
 | 
			
		||||
* **sqlite:** improve parser to handle tables without column types and fix column detection ([#914](https://github.com/chartdb/chartdb/issues/914)) ([d3dbf41](https://github.com/chartdb/chartdb/commit/d3dbf41894d74f0ffce9afe3bd810f065aa53017))
 | 
			
		||||
* trigger edit table on canvas from context menu ([#919](https://github.com/chartdb/chartdb/issues/919)) ([bdc41c0](https://github.com/chartdb/chartdb/commit/bdc41c0b74d9d9918e7b6cd2152fa07c0c58ce60))
 | 
			
		||||
* update deps vulns ([#909](https://github.com/chartdb/chartdb/issues/909)) ([2bd9ca2](https://github.com/chartdb/chartdb/commit/2bd9ca25b2c7b1f053ff4fdc8c5cfc1b0e65901d))
 | 
			
		||||
* upgrade dbml lib ([#880](https://github.com/chartdb/chartdb/issues/880)) ([d8e0bc7](https://github.com/chartdb/chartdb/commit/d8e0bc7db8881971ddaea7177bcebee13cc865f6))
 | 
			
		||||
 | 
			
		||||
## [1.15.1](https://github.com/chartdb/chartdb/compare/v1.15.0...v1.15.1) (2025-08-27)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* add actions menu to diagram list + add duplicate diagram ([#876](https://github.com/chartdb/chartdb/issues/876)) ([abd2a6c](https://github.com/chartdb/chartdb/commit/abd2a6ccbe1aa63db44ec28b3eff525cc5d3f8b0))
 | 
			
		||||
* **custom-types:** Make schema optional ([#866](https://github.com/chartdb/chartdb/issues/866)) ([60c5675](https://github.com/chartdb/chartdb/commit/60c5675cbfe205859d2d0c9848d8345a0a854671))
 | 
			
		||||
* handle quoted identifiers with special characters in SQL import/export and DBML generation ([#877](https://github.com/chartdb/chartdb/issues/877)) ([66b0863](https://github.com/chartdb/chartdb/commit/66b086378cd63347acab5fc7f13db7db4feaa872))
 | 
			
		||||
 | 
			
		||||
## [1.15.0](https://github.com/chartdb/chartdb/compare/v1.14.0...v1.15.0) (2025-08-26)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* add auto increment support for fields with database-specific export ([#851](https://github.com/chartdb/chartdb/issues/851)) ([c77c983](https://github.com/chartdb/chartdb/commit/c77c983989ae38a6b1139dd9015f4f3178d4e103))
 | 
			
		||||
* **filter:** filter tables by areas ([#836](https://github.com/chartdb/chartdb/issues/836)) ([e9c5442](https://github.com/chartdb/chartdb/commit/e9c5442d9df2beadad78187da3363bb6406636c4))
 | 
			
		||||
* include foreign keys inline in SQLite CREATE TABLE statements ([#833](https://github.com/chartdb/chartdb/issues/833)) ([43fc1d7](https://github.com/chartdb/chartdb/commit/43fc1d7fc26876b22c61405f6c3df89fc66b7992))
 | 
			
		||||
* **postgres:** add support hash index types ([#812](https://github.com/chartdb/chartdb/issues/812)) ([0d623a8](https://github.com/chartdb/chartdb/commit/0d623a86b1cb7cbd223e10ad23d09fc0e106c006))
 | 
			
		||||
* support create views ([#868](https://github.com/chartdb/chartdb/issues/868)) ([0a5874a](https://github.com/chartdb/chartdb/commit/0a5874a69b6323145430c1fb4e3482ac7da4916c))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* area filter logic ([#861](https://github.com/chartdb/chartdb/issues/861)) ([73daf0d](https://github.com/chartdb/chartdb/commit/73daf0df2142a29c2eeebe60b43198bcca869026))
 | 
			
		||||
* **area filter:** fix dragging tables over filtered areas ([#842](https://github.com/chartdb/chartdb/issues/842)) ([19fd94c](https://github.com/chartdb/chartdb/commit/19fd94c6bde3a9ec749cd1ccacbedb6abc96d037))
 | 
			
		||||
* **canvas:** delete table + area together bug ([#859](https://github.com/chartdb/chartdb/issues/859)) ([b697e26](https://github.com/chartdb/chartdb/commit/b697e26170da95dcb427ff6907b6f663c98ba59f))
 | 
			
		||||
* **cla:** Harden action ([#867](https://github.com/chartdb/chartdb/issues/867)) ([ad8e344](https://github.com/chartdb/chartdb/commit/ad8e34483fdf4226de76c9e7768bc2ba9bf154de))
 | 
			
		||||
* DBML export error with multi-line table comments for SQL Server ([#852](https://github.com/chartdb/chartdb/issues/852)) ([0545b41](https://github.com/chartdb/chartdb/commit/0545b411407b2449220d10981a04c3e368a90ca3))
 | 
			
		||||
* filter to default schema on load new diagram ([#849](https://github.com/chartdb/chartdb/issues/849)) ([712bdf5](https://github.com/chartdb/chartdb/commit/712bdf5b958919d940c4f2a1c3b7c7e969990f02))
 | 
			
		||||
* **filter:** filter toggle issues with no schemas dbs ([#856](https://github.com/chartdb/chartdb/issues/856)) ([d0dee84](https://github.com/chartdb/chartdb/commit/d0dee849702161d979b4f589a7e6579fbaade22d))
 | 
			
		||||
* **filters:** refactor diagram filters - remove schema filter ([#832](https://github.com/chartdb/chartdb/issues/832)) ([4f1d329](https://github.com/chartdb/chartdb/commit/4f1d3295c09782ab46d82ce21b662032aa094f22))
 | 
			
		||||
* for sqlite import - add more types & include type parameters ([#834](https://github.com/chartdb/chartdb/issues/834)) ([5936500](https://github.com/chartdb/chartdb/commit/5936500ca00a57b3f161616264c26152a13c36d2))
 | 
			
		||||
* improve creating view to table dependency ([#874](https://github.com/chartdb/chartdb/issues/874)) ([44be48f](https://github.com/chartdb/chartdb/commit/44be48ff3ad1361279331c17364090b13af471a1))
 | 
			
		||||
* initially show filter when filter active ([#853](https://github.com/chartdb/chartdb/issues/853)) ([ab4845c](https://github.com/chartdb/chartdb/commit/ab4845c7728e6e0b2d852f8005921fd90630eef9))
 | 
			
		||||
* **menu:** clear file menu ([#843](https://github.com/chartdb/chartdb/issues/843)) ([eaebe34](https://github.com/chartdb/chartdb/commit/eaebe3476824af779214a354b3e991923a22f195))
 | 
			
		||||
* merge relationship & dependency sections to ref section ([#870](https://github.com/chartdb/chartdb/issues/870)) ([ec3719e](https://github.com/chartdb/chartdb/commit/ec3719ebce4664b2aa6e3322fb3337e72bc21015))
 | 
			
		||||
* move dbml into sections menu ([#862](https://github.com/chartdb/chartdb/issues/862)) ([2531a70](https://github.com/chartdb/chartdb/commit/2531a7023f36ef29e67c0da6bca4fd0346b18a51))
 | 
			
		||||
* open filter by default ([#863](https://github.com/chartdb/chartdb/issues/863)) ([7e0fdd1](https://github.com/chartdb/chartdb/commit/7e0fdd1595bffe29e769d29602d04f42edfe417e))
 | 
			
		||||
* preserve composite primary key constraint names across import/export workflows ([#869](https://github.com/chartdb/chartdb/issues/869)) ([215d579](https://github.com/chartdb/chartdb/commit/215d57979df2e91fa61988acff590daad2f4e771))
 | 
			
		||||
* prevent false change detection in DBML editor by stripping public schema on import ([#858](https://github.com/chartdb/chartdb/issues/858)) ([0aaa451](https://github.com/chartdb/chartdb/commit/0aaa451479911d047e4cc83f063afa68a122ba9b))
 | 
			
		||||
* remove unnecessary space ([#845](https://github.com/chartdb/chartdb/issues/845)) ([f1a4298](https://github.com/chartdb/chartdb/commit/f1a429836221aacdda73b91665bf33ffb011164c))
 | 
			
		||||
* reorder with areas ([#846](https://github.com/chartdb/chartdb/issues/846)) ([d7c9536](https://github.com/chartdb/chartdb/commit/d7c9536272cf1d42104b7064ea448d128d091a20))
 | 
			
		||||
* **select-box:** fix select box issue in dialog ([#840](https://github.com/chartdb/chartdb/issues/840)) ([cb2ba66](https://github.com/chartdb/chartdb/commit/cb2ba66233c8c04e2d963cf2d210499d8512a268))
 | 
			
		||||
* set default filter only if has more than 1 schemas ([#855](https://github.com/chartdb/chartdb/issues/855)) ([b4ccfcd](https://github.com/chartdb/chartdb/commit/b4ccfcdcde2f3565b0d3bbc46fa1715feb6cd925))
 | 
			
		||||
* show default schema first ([#854](https://github.com/chartdb/chartdb/issues/854)) ([1759b0b](https://github.com/chartdb/chartdb/commit/1759b0b9f271ed25f7c71f26c344e3f1d97bc5fb))
 | 
			
		||||
* **sidebar:** add titles to sidebar ([#844](https://github.com/chartdb/chartdb/issues/844)) ([b8f2141](https://github.com/chartdb/chartdb/commit/b8f2141bd2e67272030896fb4009a7925f9f09e4))
 | 
			
		||||
* **sql-import:** fix SQL Server foreign key parsing for tables without schema prefix ([#857](https://github.com/chartdb/chartdb/issues/857)) ([04d91c6](https://github.com/chartdb/chartdb/commit/04d91c67b1075e94948f75186878e633df7abbca))
 | 
			
		||||
* **table colors:** switch to default table color ([#841](https://github.com/chartdb/chartdb/issues/841)) ([0da3cae](https://github.com/chartdb/chartdb/commit/0da3caeeac37926dd22f38d98423611f39c0412a))
 | 
			
		||||
* update filter on adding table ([#838](https://github.com/chartdb/chartdb/issues/838)) ([41ba251](https://github.com/chartdb/chartdb/commit/41ba25137789dda25266178cd7c96ecbb37e62a4))
 | 
			
		||||
 | 
			
		||||
## [1.14.0](https://github.com/chartdb/chartdb/compare/v1.13.2...v1.14.0) (2025-08-04)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* add floating "Show All" button when tables are out of view ([#787](https://github.com/chartdb/chartdb/issues/787)) ([bda150d](https://github.com/chartdb/chartdb/commit/bda150d4b6d6fb90beb423efba69349d21a037a5))
 | 
			
		||||
* add table selection for large database imports ([#776](https://github.com/chartdb/chartdb/issues/776)) ([0d9f57a](https://github.com/chartdb/chartdb/commit/0d9f57a9c969a67e350d6bf25e07c3a9ef5bba39))
 | 
			
		||||
* **canvas:** Add filter tables on canvas ([#774](https://github.com/chartdb/chartdb/issues/774)) ([dfbcf05](https://github.com/chartdb/chartdb/commit/dfbcf05b2f595f5b7b77dd61abf77e6e07acaf8f))
 | 
			
		||||
* **custom-types:** add highlight fields option for custom types ([#726](https://github.com/chartdb/chartdb/issues/726)) ([7e0483f](https://github.com/chartdb/chartdb/commit/7e0483f1a5512a6a737baf61caf7513e043f2e96))
 | 
			
		||||
* **datatypes:** Add decimal / numeric attribute support + organize field row ([#715](https://github.com/chartdb/chartdb/issues/715)) ([778f85d](https://github.com/chartdb/chartdb/commit/778f85d49214232a39710e47bb5d4ec41b75d427))
 | 
			
		||||
* **dbml:** Edit Diagram Directly from DBML ([#819](https://github.com/chartdb/chartdb/issues/819)) ([1b0390f](https://github.com/chartdb/chartdb/commit/1b0390f0b7652fe415540b7942cf53ec87143f08))
 | 
			
		||||
* **default value:** add default value option to table field settings ([#770](https://github.com/chartdb/chartdb/issues/770)) ([c9ea7da](https://github.com/chartdb/chartdb/commit/c9ea7da0923ff991cb936235674d9a52b8186137))
 | 
			
		||||
* enhance primary key and unique field handling logic ([#817](https://github.com/chartdb/chartdb/issues/817)) ([39247b7](https://github.com/chartdb/chartdb/commit/39247b77a299caa4f29ea434af3028155c6d37ed))
 | 
			
		||||
* implement area grouping with parent-child relationships ([#762](https://github.com/chartdb/chartdb/issues/762)) ([b35e175](https://github.com/chartdb/chartdb/commit/b35e17526b3c9b918928ae5f3f89711ea7b2529c))
 | 
			
		||||
* **schema:** support create new schema ([#801](https://github.com/chartdb/chartdb/issues/801)) ([867903c](https://github.com/chartdb/chartdb/commit/867903cd5f24d96ce1fe718dc9b562e2f2b75276))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
* add open and create diagram to side menu ([#757](https://github.com/chartdb/chartdb/issues/757)) ([67f5ac3](https://github.com/chartdb/chartdb/commit/67f5ac303ebf5ada97d5c80fb08a2815ca205a91))
 | 
			
		||||
* add PostgreSQL tests and fix parsing SQL ([#760](https://github.com/chartdb/chartdb/issues/760)) ([5d33740](https://github.com/chartdb/chartdb/commit/5d337409d64d1078b538350016982a98e684c06c))
 | 
			
		||||
* area resizers size ([#830](https://github.com/chartdb/chartdb/issues/830)) ([23e93bf](https://github.com/chartdb/chartdb/commit/23e93bfd01d741dd3d11aa5c479cef97e1a86fa6))
 | 
			
		||||
* **area:** redo/undo after dragging an area with tables ([#767](https://github.com/chartdb/chartdb/issues/767)) ([6af94af](https://github.com/chartdb/chartdb/commit/6af94afc56cf8987b8fc9e3f0a9bfa966de35408))
 | 
			
		||||
* **canvas filter:** improve scroller on canvas filter ([#799](https://github.com/chartdb/chartdb/issues/799)) ([6bea827](https://github.com/chartdb/chartdb/commit/6bea82729362a8c7b73dc089ddd9e52bae176aa2))
 | 
			
		||||
* **canvas:** fix filter eye button ([#780](https://github.com/chartdb/chartdb/issues/780)) ([b7dbe54](https://github.com/chartdb/chartdb/commit/b7dbe54c83c75cfe3c556f7a162055dcfe2de23d))
 | 
			
		||||
* clone of custom types ([#804](https://github.com/chartdb/chartdb/issues/804)) ([b30162d](https://github.com/chartdb/chartdb/commit/b30162d98bc659a61aae023cdeaead4ce25c7ae9))
 | 
			
		||||
* **cockroachdb:** support schema creation for cockroachdb ([#803](https://github.com/chartdb/chartdb/issues/803)) ([dba372d](https://github.com/chartdb/chartdb/commit/dba372d25a8c642baf8600d05aa154882729d446))
 | 
			
		||||
* **dbml actions:** set dbml tooltips side ([#798](https://github.com/chartdb/chartdb/issues/798)) ([a119854](https://github.com/chartdb/chartdb/commit/a119854da7c935eb595984ea9398e04136ce60c4))
 | 
			
		||||
* **dbml editor:** move tooltips button to be on the right ([#797](https://github.com/chartdb/chartdb/issues/797)) ([bfbfd7b](https://github.com/chartdb/chartdb/commit/bfbfd7b843f96c894b1966ad95393b866c927466))
 | 
			
		||||
* **dbml export:** fix handle tables with same name under different schemas ([#807](https://github.com/chartdb/chartdb/issues/807)) ([18e9142](https://github.com/chartdb/chartdb/commit/18e914242faccd6376fe5a7cd5a4478667f065ee))
 | 
			
		||||
* **dbml export:** handle tables with same name under different schemas ([#806](https://github.com/chartdb/chartdb/issues/806)) ([e68837a](https://github.com/chartdb/chartdb/commit/e68837a34aa635fb6fc02c7f1289495e5c448242))
 | 
			
		||||
* **dbml field comments:** support export field comments in dbml ([#796](https://github.com/chartdb/chartdb/issues/796)) ([0ca7008](https://github.com/chartdb/chartdb/commit/0ca700873577bbfbf1dd3f8088c258fc89b10c53))
 | 
			
		||||
* **dbml import:** fix dbml import types + schemas ([#808](https://github.com/chartdb/chartdb/issues/808)) ([00bd535](https://github.com/chartdb/chartdb/commit/00bd535b3c62d26d25a6276d52beb10e26afad76))
 | 
			
		||||
* **dbml-export:** merge field attributes into single brackets and fix schema syntax ([#790](https://github.com/chartdb/chartdb/issues/790)) ([309ee9c](https://github.com/chartdb/chartdb/commit/309ee9cb0ff1f5a68ed183e3919e1a11a8410909))
 | 
			
		||||
* **dbml-import:** handle unsupported DBML features and add comprehensive tests ([#766](https://github.com/chartdb/chartdb/issues/766)) ([22d46e1](https://github.com/chartdb/chartdb/commit/22d46e1e90729730cc25dd6961bfe8c3d2ae0c98))
 | 
			
		||||
* **dbml:** dbml indentation ([#829](https://github.com/chartdb/chartdb/issues/829)) ([16f9f46](https://github.com/chartdb/chartdb/commit/16f9f4671e011eb66ba9594bed47570eda3eed66))
 | 
			
		||||
* **dbml:** dbml note syntax ([#826](https://github.com/chartdb/chartdb/issues/826)) ([337f7cd](https://github.com/chartdb/chartdb/commit/337f7cdab4759d15cb4d25a8c0e9394e99ba33d4))
 | 
			
		||||
* **dbml:** fix dbml output format ([#815](https://github.com/chartdb/chartdb/issues/815)) ([eed104b](https://github.com/chartdb/chartdb/commit/eed104be5ba2b7d9940ffac38e7877722ad764fc))
 | 
			
		||||
* **dbml:** fix schemas with same table names ([#828](https://github.com/chartdb/chartdb/issues/828)) ([0c300e5](https://github.com/chartdb/chartdb/commit/0c300e5e72cc5ff22cac42f8dbaed167061157c6))
 | 
			
		||||
* **dbml:** import dbml notes (table + fields) ([#827](https://github.com/chartdb/chartdb/issues/827)) ([b9a1e78](https://github.com/chartdb/chartdb/commit/b9a1e78b53c932c0b1a12ee38b62494a5c2f9348))
 | 
			
		||||
* **dbml:** support multiple relationships on same field in inline DBML ([#822](https://github.com/chartdb/chartdb/issues/822)) ([a5f8e56](https://github.com/chartdb/chartdb/commit/a5f8e56b3ca97b851b6953481644d3a3ff7ce882))
 | 
			
		||||
* **dbml:** support spaces in names ([#794](https://github.com/chartdb/chartdb/issues/794)) ([8f27f10](https://github.com/chartdb/chartdb/commit/8f27f10dec96af400dc2c12a30b22b3a346803a9))
 | 
			
		||||
* fix hotkeys on form elements ([#778](https://github.com/chartdb/chartdb/issues/778)) ([43d1dff](https://github.com/chartdb/chartdb/commit/43d1dfff71f2b960358a79b0112b78d11df91fb7))
 | 
			
		||||
* fix screen freeze after schema select ([#800](https://github.com/chartdb/chartdb/issues/800)) ([8aeb1df](https://github.com/chartdb/chartdb/commit/8aeb1df0ad353c49e91243453f24bfa5921a89ab))
 | 
			
		||||
* **i18n:** add Croatian (hr) language support ([#802](https://github.com/chartdb/chartdb/issues/802)) ([2eb48e7](https://github.com/chartdb/chartdb/commit/2eb48e75d303d622f51327d22502a6f78e7fb32d))
 | 
			
		||||
* improve SQL export formatting and add schema-aware FK grouping ([#783](https://github.com/chartdb/chartdb/issues/783)) ([6df588f](https://github.com/chartdb/chartdb/commit/6df588f40e6e7066da6125413b94466429d48767))
 | 
			
		||||
* lost in canvas button animation ([#793](https://github.com/chartdb/chartdb/issues/793)) ([a93ec2c](https://github.com/chartdb/chartdb/commit/a93ec2cab906d0e4431d8d1668adcf2dbfc3c80f))
 | 
			
		||||
* **readonly:** fix zoom out on readonly ([#818](https://github.com/chartdb/chartdb/issues/818)) ([8ffde62](https://github.com/chartdb/chartdb/commit/8ffde62c1a00893c4bf6b4dd39068df530375416))
 | 
			
		||||
* remove error lag after autofix ([#764](https://github.com/chartdb/chartdb/issues/764)) ([bf32c08](https://github.com/chartdb/chartdb/commit/bf32c08d37c02ee6d7946a41633bb97b2271fcb7))
 | 
			
		||||
* remove unnecessary import ([#791](https://github.com/chartdb/chartdb/issues/791)) ([87836e5](https://github.com/chartdb/chartdb/commit/87836e53d145b825f9c4f80abca72f418df50e6c))
 | 
			
		||||
* **scroll:** disable scroll x behavior ([#795](https://github.com/chartdb/chartdb/issues/795)) ([4bc71c5](https://github.com/chartdb/chartdb/commit/4bc71c52ff5c462800d8530b72a5aadb7d7f85ed))
 | 
			
		||||
* set focus on filter search ([#775](https://github.com/chartdb/chartdb/issues/775)) ([9949a46](https://github.com/chartdb/chartdb/commit/9949a46ee3ba7f46a2ea7f2c0d7101cc9336df4f))
 | 
			
		||||
* solve issue with multiple render of tables ([#823](https://github.com/chartdb/chartdb/issues/823)) ([0c7eaa2](https://github.com/chartdb/chartdb/commit/0c7eaa2df20cfb6994b7e6251c760a2d4581c879))
 | 
			
		||||
* **sql-export:** escape newlines and quotes in multi-line comments ([#765](https://github.com/chartdb/chartdb/issues/765)) ([f7f9290](https://github.com/chartdb/chartdb/commit/f7f92903def84a94ac0c66f625f96a6681383945))
 | 
			
		||||
* **sql-server:** improvment for sql-server import via sql script ([#789](https://github.com/chartdb/chartdb/issues/789)) ([79b8855](https://github.com/chartdb/chartdb/commit/79b885502e3385e996a52093a3ccd5f6e469993a))
 | 
			
		||||
* **table-node:** fix comment icon on field ([#786](https://github.com/chartdb/chartdb/issues/786)) ([745bdee](https://github.com/chartdb/chartdb/commit/745bdee86d07f1e9c3a2d24237c48c25b9a8eeea))
 | 
			
		||||
* **table-node:** improve field spacing ([#785](https://github.com/chartdb/chartdb/issues/785)) ([08eb9cc](https://github.com/chartdb/chartdb/commit/08eb9cc55f0077f53afea6f9ce720341e1a583c2))
 | 
			
		||||
* **table-select:** add loading indication for import ([#782](https://github.com/chartdb/chartdb/issues/782)) ([b46ed58](https://github.com/chartdb/chartdb/commit/b46ed58dff1ec74579fb1544dba46b0f77730c52))
 | 
			
		||||
* **ui:** reduce spacing between primary key icon and short field types ([#816](https://github.com/chartdb/chartdb/issues/816)) ([984b2ae](https://github.com/chartdb/chartdb/commit/984b2aeee22c43cb9bda77df2c22087973079af4))
 | 
			
		||||
* update MariaDB database import smart query ([#792](https://github.com/chartdb/chartdb/issues/792)) ([386e40a](https://github.com/chartdb/chartdb/commit/386e40a0bf93d9aef1486bb1e729d8f485e675eb))
 | 
			
		||||
* update multiple schemas toast to require user action ([#771](https://github.com/chartdb/chartdb/issues/771)) ([f56fab9](https://github.com/chartdb/chartdb/commit/f56fab9876fb9fc46c6c708231324a90d8a7851d))
 | 
			
		||||
* update relationship when table width changes via expand/shrink ([#825](https://github.com/chartdb/chartdb/issues/825)) ([bc52933](https://github.com/chartdb/chartdb/commit/bc52933b58bfe6bc73779d9401128254cbf497d5))
 | 
			
		||||
 | 
			
		||||
## [1.13.2](https://github.com/chartdb/chartdb/compare/v1.13.1...v1.13.2) (2025-07-06)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								index.html
									
									
									
									
									
								
							@@ -4,9 +4,8 @@
 | 
			
		||||
        <meta charset="UTF-8" />
 | 
			
		||||
        <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
 | 
			
		||||
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
        <meta name="robots" content="noindex, max-image-preview:large" />
 | 
			
		||||
        <meta name="robots" content="max-image-preview:large" />
 | 
			
		||||
        <title>ChartDB - Create & Visualize Database Schema Diagrams</title>
 | 
			
		||||
        <link rel="canonical" href="https://chartdb.io" />
 | 
			
		||||
        <link rel="preconnect" href="https://fonts.googleapis.com" />
 | 
			
		||||
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
 | 
			
		||||
        <link
 | 
			
		||||
@@ -16,19 +15,14 @@
 | 
			
		||||
        <script src="/config.js"></script>
 | 
			
		||||
        <script>
 | 
			
		||||
            // Load analytics only if not disabled
 | 
			
		||||
            (function () {
 | 
			
		||||
                const disableAnalytics =
 | 
			
		||||
                    (window.env && window.env.DISABLE_ANALYTICS === 'true') ||
 | 
			
		||||
                    (typeof process !== 'undefined' &&
 | 
			
		||||
                        process.env &&
 | 
			
		||||
                        process.env.VITE_DISABLE_ANALYTICS === 'true');
 | 
			
		||||
            (function() {
 | 
			
		||||
                const disableAnalytics = (window.env && window.env.DISABLE_ANALYTICS === 'true') ||
 | 
			
		||||
                                        (typeof process !== 'undefined' && process.env && process.env.VITE_DISABLE_ANALYTICS === 'true');
 | 
			
		||||
 | 
			
		||||
                if (!disableAnalytics) {
 | 
			
		||||
                    const script = document.createElement('script');
 | 
			
		||||
                    script.src = 'https://cdn.usefathom.com/script.js';
 | 
			
		||||
                    script.setAttribute('data-site', 'PRHIVBNN');
 | 
			
		||||
                    script.setAttribute('data-canonical', 'false');
 | 
			
		||||
                    script.setAttribute('data-spa', 'auto');
 | 
			
		||||
                    script.defer = true;
 | 
			
		||||
                    document.head.appendChild(script);
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										881
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										881
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										14
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								package.json
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "chartdb",
 | 
			
		||||
    "private": true,
 | 
			
		||||
    "version": "1.17.0",
 | 
			
		||||
    "version": "1.13.2",
 | 
			
		||||
    "type": "module",
 | 
			
		||||
    "scripts": {
 | 
			
		||||
        "dev": "vite",
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@ai-sdk/openai": "^0.0.51",
 | 
			
		||||
        "@dbml/core": "^3.13.9",
 | 
			
		||||
        "@dbml/core": "^3.9.5",
 | 
			
		||||
        "@dnd-kit/sortable": "^8.0.0",
 | 
			
		||||
        "@monaco-editor/react": "^4.6.0",
 | 
			
		||||
        "@radix-ui/react-accordion": "^1.2.0",
 | 
			
		||||
@@ -26,24 +26,24 @@
 | 
			
		||||
        "@radix-ui/react-checkbox": "^1.1.1",
 | 
			
		||||
        "@radix-ui/react-collapsible": "^1.1.0",
 | 
			
		||||
        "@radix-ui/react-context-menu": "^2.2.1",
 | 
			
		||||
        "@radix-ui/react-dialog": "^1.1.14",
 | 
			
		||||
        "@radix-ui/react-dialog": "^1.1.6",
 | 
			
		||||
        "@radix-ui/react-dropdown-menu": "^2.1.1",
 | 
			
		||||
        "@radix-ui/react-hover-card": "^1.1.1",
 | 
			
		||||
        "@radix-ui/react-icons": "^1.3.2",
 | 
			
		||||
        "@radix-ui/react-icons": "^1.3.0",
 | 
			
		||||
        "@radix-ui/react-label": "^2.1.0",
 | 
			
		||||
        "@radix-ui/react-menubar": "^1.1.1",
 | 
			
		||||
        "@radix-ui/react-popover": "^1.1.1",
 | 
			
		||||
        "@radix-ui/react-scroll-area": "1.2.0",
 | 
			
		||||
        "@radix-ui/react-select": "^2.1.1",
 | 
			
		||||
        "@radix-ui/react-separator": "^1.1.7",
 | 
			
		||||
        "@radix-ui/react-separator": "^1.1.2",
 | 
			
		||||
        "@radix-ui/react-slot": "^1.2.3",
 | 
			
		||||
        "@radix-ui/react-tabs": "^1.1.0",
 | 
			
		||||
        "@radix-ui/react-toast": "^1.2.1",
 | 
			
		||||
        "@radix-ui/react-toggle": "^1.1.0",
 | 
			
		||||
        "@radix-ui/react-toggle-group": "^1.1.0",
 | 
			
		||||
        "@radix-ui/react-tooltip": "^1.2.7",
 | 
			
		||||
        "@radix-ui/react-tooltip": "^1.1.8",
 | 
			
		||||
        "@uidotdev/usehooks": "^2.4.1",
 | 
			
		||||
        "@xyflow/react": "^12.8.2",
 | 
			
		||||
        "@xyflow/react": "^12.3.1",
 | 
			
		||||
        "ahooks": "^3.8.1",
 | 
			
		||||
        "ai": "^3.3.14",
 | 
			
		||||
        "class-variance-authority": "^0.7.1",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
User-agent: *
 | 
			
		||||
Disallow: /
 | 
			
		||||
Allow: /
 | 
			
		||||
 | 
			
		||||
Sitemap: https://app.chartdb.io/sitemap.xml
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import { cva } from 'class-variance-authority';
 | 
			
		||||
 | 
			
		||||
export const buttonVariants = cva(
 | 
			
		||||
    'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
 | 
			
		||||
    'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
 | 
			
		||||
    {
 | 
			
		||||
        variants: {
 | 
			
		||||
            variant: {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,137 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { ChevronDownIcon } from '@radix-ui/react-icons';
 | 
			
		||||
import { Slot } from '@radix-ui/react-slot';
 | 
			
		||||
import { type VariantProps } from 'class-variance-authority';
 | 
			
		||||
 | 
			
		||||
import { cn } from '@/lib/utils';
 | 
			
		||||
import { buttonVariants } from './button-variants';
 | 
			
		||||
import {
 | 
			
		||||
    DropdownMenu,
 | 
			
		||||
    DropdownMenuContent,
 | 
			
		||||
    DropdownMenuItem,
 | 
			
		||||
    DropdownMenuTrigger,
 | 
			
		||||
} from '@/components/dropdown-menu/dropdown-menu';
 | 
			
		||||
import {
 | 
			
		||||
    Tooltip,
 | 
			
		||||
    TooltipContent,
 | 
			
		||||
    TooltipTrigger,
 | 
			
		||||
} from '@/components/tooltip/tooltip';
 | 
			
		||||
 | 
			
		||||
export interface ButtonAlternative {
 | 
			
		||||
    label: string;
 | 
			
		||||
    onClick: () => void;
 | 
			
		||||
    disabled?: boolean;
 | 
			
		||||
    icon?: React.ReactNode;
 | 
			
		||||
    className?: string;
 | 
			
		||||
    tooltip?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ButtonWithAlternativesProps
 | 
			
		||||
    extends React.ButtonHTMLAttributes<HTMLButtonElement>,
 | 
			
		||||
        VariantProps<typeof buttonVariants> {
 | 
			
		||||
    asChild?: boolean;
 | 
			
		||||
    alternatives: Array<ButtonAlternative>;
 | 
			
		||||
    dropdownTriggerClassName?: string;
 | 
			
		||||
    chevronDownIconClassName?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ButtonWithAlternatives = React.forwardRef<
 | 
			
		||||
    HTMLButtonElement,
 | 
			
		||||
    ButtonWithAlternativesProps
 | 
			
		||||
>(
 | 
			
		||||
    (
 | 
			
		||||
        {
 | 
			
		||||
            className,
 | 
			
		||||
            variant,
 | 
			
		||||
            size,
 | 
			
		||||
            asChild = false,
 | 
			
		||||
            alternatives,
 | 
			
		||||
            children,
 | 
			
		||||
            onClick,
 | 
			
		||||
            dropdownTriggerClassName,
 | 
			
		||||
            chevronDownIconClassName,
 | 
			
		||||
            ...props
 | 
			
		||||
        },
 | 
			
		||||
        ref
 | 
			
		||||
    ) => {
 | 
			
		||||
        const Comp = asChild ? Slot : 'button';
 | 
			
		||||
        const hasAlternatives = (alternatives?.length ?? 0) > 0;
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <div className="inline-flex items-stretch">
 | 
			
		||||
                <Comp
 | 
			
		||||
                    className={cn(
 | 
			
		||||
                        buttonVariants({ variant, size }),
 | 
			
		||||
                        { 'rounded-r-none': hasAlternatives },
 | 
			
		||||
                        className
 | 
			
		||||
                    )}
 | 
			
		||||
                    ref={ref}
 | 
			
		||||
                    onClick={onClick}
 | 
			
		||||
                    {...props}
 | 
			
		||||
                >
 | 
			
		||||
                    {children}
 | 
			
		||||
                </Comp>
 | 
			
		||||
                {hasAlternatives ? (
 | 
			
		||||
                    <DropdownMenu>
 | 
			
		||||
                        <DropdownMenuTrigger asChild>
 | 
			
		||||
                            <button
 | 
			
		||||
                                className={cn(
 | 
			
		||||
                                    buttonVariants({ variant, size }),
 | 
			
		||||
                                    'rounded-l-none border-l border-l-primary/5 px-2 min-w-0',
 | 
			
		||||
                                    className?.includes('h-') &&
 | 
			
		||||
                                        className.match(/h-\d+/)?.[0],
 | 
			
		||||
                                    className?.includes('text-') &&
 | 
			
		||||
                                        className.match(/text-\w+/)?.[0],
 | 
			
		||||
                                    dropdownTriggerClassName
 | 
			
		||||
                                )}
 | 
			
		||||
                                type="button"
 | 
			
		||||
                            >
 | 
			
		||||
                                <ChevronDownIcon
 | 
			
		||||
                                    className={cn(
 | 
			
		||||
                                        'size-4 shrink-0',
 | 
			
		||||
                                        chevronDownIconClassName
 | 
			
		||||
                                    )}
 | 
			
		||||
                                />
 | 
			
		||||
                            </button>
 | 
			
		||||
                        </DropdownMenuTrigger>
 | 
			
		||||
                        <DropdownMenuContent align="end">
 | 
			
		||||
                            {alternatives.map((alternative, index) => {
 | 
			
		||||
                                const menuItem = (
 | 
			
		||||
                                    <DropdownMenuItem
 | 
			
		||||
                                        key={index}
 | 
			
		||||
                                        onClick={alternative.onClick}
 | 
			
		||||
                                        disabled={alternative.disabled}
 | 
			
		||||
                                        className={cn(alternative.className)}
 | 
			
		||||
                                    >
 | 
			
		||||
                                        <span className="flex w-full items-center justify-between gap-2">
 | 
			
		||||
                                            {alternative.label}
 | 
			
		||||
                                            {alternative.icon}
 | 
			
		||||
                                        </span>
 | 
			
		||||
                                    </DropdownMenuItem>
 | 
			
		||||
                                );
 | 
			
		||||
 | 
			
		||||
                                if (alternative.tooltip) {
 | 
			
		||||
                                    return (
 | 
			
		||||
                                        <Tooltip key={index}>
 | 
			
		||||
                                            <TooltipTrigger asChild>
 | 
			
		||||
                                                {menuItem}
 | 
			
		||||
                                            </TooltipTrigger>
 | 
			
		||||
                                            <TooltipContent side="left">
 | 
			
		||||
                                                {alternative.tooltip}
 | 
			
		||||
                                            </TooltipContent>
 | 
			
		||||
                                        </Tooltip>
 | 
			
		||||
                                    );
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                return menuItem;
 | 
			
		||||
                            })}
 | 
			
		||||
                        </DropdownMenuContent>
 | 
			
		||||
                    </DropdownMenu>
 | 
			
		||||
                ) : null}
 | 
			
		||||
            </div>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
ButtonWithAlternatives.displayName = 'ButtonWithAlternatives';
 | 
			
		||||
 | 
			
		||||
export { ButtonWithAlternatives };
 | 
			
		||||
@@ -31,21 +31,18 @@ export interface CodeSnippetAction {
 | 
			
		||||
    label: string;
 | 
			
		||||
    icon: LucideIcon;
 | 
			
		||||
    onClick: () => void;
 | 
			
		||||
    className?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CodeSnippetProps {
 | 
			
		||||
    className?: string;
 | 
			
		||||
    code: string;
 | 
			
		||||
    codeToCopy?: string;
 | 
			
		||||
    language?: 'sql' | 'shell' | 'dbml';
 | 
			
		||||
    language?: 'sql' | 'shell';
 | 
			
		||||
    loading?: boolean;
 | 
			
		||||
    autoScroll?: boolean;
 | 
			
		||||
    isComplete?: boolean;
 | 
			
		||||
    editorProps?: React.ComponentProps<EditorType>;
 | 
			
		||||
    actions?: CodeSnippetAction[];
 | 
			
		||||
    actionsTooltipSide?: 'top' | 'right' | 'bottom' | 'left';
 | 
			
		||||
    allowCopy?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo(
 | 
			
		||||
@@ -59,8 +56,6 @@ export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo(
 | 
			
		||||
        isComplete = true,
 | 
			
		||||
        editorProps,
 | 
			
		||||
        actions,
 | 
			
		||||
        actionsTooltipSide,
 | 
			
		||||
        allowCopy = true,
 | 
			
		||||
    }) => {
 | 
			
		||||
        const { t } = useTranslation();
 | 
			
		||||
        const monaco = useMonaco();
 | 
			
		||||
@@ -134,37 +129,33 @@ export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo(
 | 
			
		||||
                    <Suspense fallback={<Spinner />}>
 | 
			
		||||
                        {isComplete ? (
 | 
			
		||||
                            <div className="absolute right-1 top-1 z-10 flex flex-col gap-1">
 | 
			
		||||
                                {allowCopy ? (
 | 
			
		||||
                                    <Tooltip
 | 
			
		||||
                                        onOpenChange={setTooltipOpen}
 | 
			
		||||
                                        open={isCopied || tooltipOpen}
 | 
			
		||||
                                    >
 | 
			
		||||
                                        <TooltipTrigger asChild>
 | 
			
		||||
                                            <span>
 | 
			
		||||
                                                <Button
 | 
			
		||||
                                                    className="h-fit p-1.5"
 | 
			
		||||
                                                    variant="outline"
 | 
			
		||||
                                                    onClick={copyToClipboard}
 | 
			
		||||
                                                >
 | 
			
		||||
                                                    {isCopied ? (
 | 
			
		||||
                                                        <CopyCheck size={16} />
 | 
			
		||||
                                                    ) : (
 | 
			
		||||
                                                        <Copy size={16} />
 | 
			
		||||
                                                    )}
 | 
			
		||||
                                                </Button>
 | 
			
		||||
                                            </span>
 | 
			
		||||
                                        </TooltipTrigger>
 | 
			
		||||
                                        <TooltipContent
 | 
			
		||||
                                            side={actionsTooltipSide}
 | 
			
		||||
                                        >
 | 
			
		||||
                                            {t(
 | 
			
		||||
                                                isCopied
 | 
			
		||||
                                                    ? 'copied'
 | 
			
		||||
                                                    : 'copy_to_clipboard'
 | 
			
		||||
                                            )}
 | 
			
		||||
                                        </TooltipContent>
 | 
			
		||||
                                    </Tooltip>
 | 
			
		||||
                                ) : null}
 | 
			
		||||
                                <Tooltip
 | 
			
		||||
                                    onOpenChange={setTooltipOpen}
 | 
			
		||||
                                    open={isCopied || tooltipOpen}
 | 
			
		||||
                                >
 | 
			
		||||
                                    <TooltipTrigger asChild>
 | 
			
		||||
                                        <span>
 | 
			
		||||
                                            <Button
 | 
			
		||||
                                                className="h-fit p-1.5"
 | 
			
		||||
                                                variant="outline"
 | 
			
		||||
                                                onClick={copyToClipboard}
 | 
			
		||||
                                            >
 | 
			
		||||
                                                {isCopied ? (
 | 
			
		||||
                                                    <CopyCheck size={16} />
 | 
			
		||||
                                                ) : (
 | 
			
		||||
                                                    <Copy size={16} />
 | 
			
		||||
                                                )}
 | 
			
		||||
                                            </Button>
 | 
			
		||||
                                        </span>
 | 
			
		||||
                                    </TooltipTrigger>
 | 
			
		||||
                                    <TooltipContent>
 | 
			
		||||
                                        {t(
 | 
			
		||||
                                            isCopied
 | 
			
		||||
                                                ? 'copied'
 | 
			
		||||
                                                : 'copy_to_clipboard'
 | 
			
		||||
                                        )}
 | 
			
		||||
                                    </TooltipContent>
 | 
			
		||||
                                </Tooltip>
 | 
			
		||||
 | 
			
		||||
                                {actions &&
 | 
			
		||||
                                    actions.length > 0 &&
 | 
			
		||||
@@ -173,10 +164,7 @@ export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo(
 | 
			
		||||
                                            <TooltipTrigger asChild>
 | 
			
		||||
                                                <span>
 | 
			
		||||
                                                    <Button
 | 
			
		||||
                                                        className={cn(
 | 
			
		||||
                                                            'h-fit p-1.5',
 | 
			
		||||
                                                            action.className
 | 
			
		||||
                                                        )}
 | 
			
		||||
                                                        className="h-fit p-1.5"
 | 
			
		||||
                                                        variant="outline"
 | 
			
		||||
                                                        onClick={action.onClick}
 | 
			
		||||
                                                    >
 | 
			
		||||
@@ -186,9 +174,7 @@ export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo(
 | 
			
		||||
                                                    </Button>
 | 
			
		||||
                                                </span>
 | 
			
		||||
                                            </TooltipTrigger>
 | 
			
		||||
                                            <TooltipContent
 | 
			
		||||
                                                side={actionsTooltipSide}
 | 
			
		||||
                                            >
 | 
			
		||||
                                            <TooltipContent>
 | 
			
		||||
                                                {action.label}
 | 
			
		||||
                                            </TooltipContent>
 | 
			
		||||
                                        </Tooltip>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,51 +0,0 @@
 | 
			
		||||
import type { DBMLError } from '@/lib/dbml/dbml-import/dbml-import-error';
 | 
			
		||||
import * as monaco from 'monaco-editor';
 | 
			
		||||
 | 
			
		||||
export const highlightErrorLine = ({
 | 
			
		||||
    error,
 | 
			
		||||
    model,
 | 
			
		||||
    editorDecorationsCollection,
 | 
			
		||||
}: {
 | 
			
		||||
    error: DBMLError;
 | 
			
		||||
    model?: monaco.editor.ITextModel | null;
 | 
			
		||||
    editorDecorationsCollection:
 | 
			
		||||
        | monaco.editor.IEditorDecorationsCollection
 | 
			
		||||
        | undefined;
 | 
			
		||||
}) => {
 | 
			
		||||
    if (!model) return;
 | 
			
		||||
    if (!editorDecorationsCollection) return;
 | 
			
		||||
 | 
			
		||||
    const decorations = [
 | 
			
		||||
        {
 | 
			
		||||
            range: new monaco.Range(
 | 
			
		||||
                error.line,
 | 
			
		||||
                1,
 | 
			
		||||
                error.line,
 | 
			
		||||
                model.getLineMaxColumn(error.line)
 | 
			
		||||
            ),
 | 
			
		||||
            options: {
 | 
			
		||||
                isWholeLine: true,
 | 
			
		||||
                className: 'dbml-error-line',
 | 
			
		||||
                glyphMarginClassName: 'dbml-error-glyph',
 | 
			
		||||
                hoverMessage: { value: error.message },
 | 
			
		||||
                overviewRuler: {
 | 
			
		||||
                    color: '#ff0000',
 | 
			
		||||
                    position: monaco.editor.OverviewRulerLane.Right,
 | 
			
		||||
                    darkColor: '#ff0000',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    editorDecorationsCollection?.set(decorations);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const clearErrorHighlight = (
 | 
			
		||||
    editorDecorationsCollection:
 | 
			
		||||
        | monaco.editor.IEditorDecorationsCollection
 | 
			
		||||
        | undefined
 | 
			
		||||
) => {
 | 
			
		||||
    if (editorDecorationsCollection) {
 | 
			
		||||
        editorDecorationsCollection.clear();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -9,14 +9,12 @@ export const setupDBMLLanguage = (monaco: Monaco) => {
 | 
			
		||||
        base: 'vs-dark',
 | 
			
		||||
        inherit: true,
 | 
			
		||||
        rules: [
 | 
			
		||||
            { token: 'comment', foreground: '6A9955' }, // Comments
 | 
			
		||||
            { token: 'keyword', foreground: '569CD6' }, // Table, Ref keywords
 | 
			
		||||
            { token: 'string', foreground: 'CE9178' }, // Strings
 | 
			
		||||
            { token: 'annotation', foreground: '9CDCFE' }, // [annotations]
 | 
			
		||||
            { token: 'delimiter', foreground: 'D4D4D4' }, // Braces {}
 | 
			
		||||
            { token: 'operator', foreground: 'D4D4D4' }, // Operators
 | 
			
		||||
            { token: 'type', foreground: '4EC9B0' }, // Data types
 | 
			
		||||
            { token: 'identifier', foreground: '9CDCFE' }, // Field names
 | 
			
		||||
            { token: 'datatype', foreground: '4EC9B0' }, // Data types
 | 
			
		||||
        ],
 | 
			
		||||
        colors: {},
 | 
			
		||||
    });
 | 
			
		||||
@@ -25,14 +23,12 @@ export const setupDBMLLanguage = (monaco: Monaco) => {
 | 
			
		||||
        base: 'vs',
 | 
			
		||||
        inherit: true,
 | 
			
		||||
        rules: [
 | 
			
		||||
            { token: 'comment', foreground: '008000' }, // Comments
 | 
			
		||||
            { token: 'keyword', foreground: '0000FF' }, // Table, Ref keywords
 | 
			
		||||
            { token: 'string', foreground: 'A31515' }, // Strings
 | 
			
		||||
            { token: 'annotation', foreground: '001080' }, // [annotations]
 | 
			
		||||
            { token: 'delimiter', foreground: '000000' }, // Braces {}
 | 
			
		||||
            { token: 'operator', foreground: '000000' }, // Operators
 | 
			
		||||
            { token: 'type', foreground: '267F99' }, // Data types
 | 
			
		||||
            { token: 'identifier', foreground: '001080' }, // Field names
 | 
			
		||||
        ],
 | 
			
		||||
        colors: {},
 | 
			
		||||
    });
 | 
			
		||||
@@ -41,63 +37,17 @@ export const setupDBMLLanguage = (monaco: Monaco) => {
 | 
			
		||||
    const datatypePattern = dataTypesNames.join('|');
 | 
			
		||||
 | 
			
		||||
    monaco.languages.setMonarchTokensProvider('dbml', {
 | 
			
		||||
        keywords: ['Table', 'Ref', 'Indexes', 'Note', 'Enum', 'enum'],
 | 
			
		||||
        keywords: ['Table', 'Ref', 'Indexes'],
 | 
			
		||||
        datatypes: dataTypesNames,
 | 
			
		||||
        operators: ['>', '<', '-'],
 | 
			
		||||
 | 
			
		||||
        tokenizer: {
 | 
			
		||||
            root: [
 | 
			
		||||
                // Comments
 | 
			
		||||
                [/\/\/.*$/, 'comment'],
 | 
			
		||||
 | 
			
		||||
                // Keywords - case insensitive
 | 
			
		||||
                [
 | 
			
		||||
                    /\b([Tt][Aa][Bb][Ll][Ee]|[Ee][Nn][Uu][Mm]|[Rr][Ee][Ff]|[Ii][Nn][Dd][Ee][Xx][Ee][Ss]|[Nn][Oo][Tt][Ee])\b/,
 | 
			
		||||
                    'keyword',
 | 
			
		||||
                ],
 | 
			
		||||
 | 
			
		||||
                // Annotations in brackets
 | 
			
		||||
                [/\b(Table|Ref|Indexes)\b/, 'keyword'],
 | 
			
		||||
                [/\[.*?\]/, 'annotation'],
 | 
			
		||||
 | 
			
		||||
                // Strings
 | 
			
		||||
                [/'''/, 'string', '@tripleQuoteString'],
 | 
			
		||||
                [/"([^"\\]|\\.)*$/, 'string.invalid'], // non-terminated string
 | 
			
		||||
                [/'([^'\\]|\\.)*$/, 'string.invalid'], // non-terminated string
 | 
			
		||||
                [/"/, 'string', '@string_double'],
 | 
			
		||||
                [/'/, 'string', '@string_single'],
 | 
			
		||||
                [/`.*?`/, 'string'],
 | 
			
		||||
 | 
			
		||||
                // Delimiters and operators
 | 
			
		||||
                [/[{}()]/, 'delimiter'],
 | 
			
		||||
                [/[<>-]/, 'operator'],
 | 
			
		||||
                [/:/, 'delimiter'],
 | 
			
		||||
 | 
			
		||||
                // Data types
 | 
			
		||||
                [new RegExp(`\\b(${datatypePattern})\\b`, 'i'), 'type'],
 | 
			
		||||
 | 
			
		||||
                // Numbers
 | 
			
		||||
                [/\d+/, 'number'],
 | 
			
		||||
 | 
			
		||||
                // Identifiers
 | 
			
		||||
                [/[a-zA-Z_]\w*/, 'identifier'],
 | 
			
		||||
            ],
 | 
			
		||||
 | 
			
		||||
            string_double: [
 | 
			
		||||
                [/[^\\"]+/, 'string'],
 | 
			
		||||
                [/\\./, 'string.escape'],
 | 
			
		||||
                [/"/, 'string', '@pop'],
 | 
			
		||||
            ],
 | 
			
		||||
 | 
			
		||||
            string_single: [
 | 
			
		||||
                [/[^\\']+/, 'string'],
 | 
			
		||||
                [/\\./, 'string.escape'],
 | 
			
		||||
                [/'/, 'string', '@pop'],
 | 
			
		||||
            ],
 | 
			
		||||
 | 
			
		||||
            tripleQuoteString: [
 | 
			
		||||
                [/[^']+/, 'string'],
 | 
			
		||||
                [/'''/, 'string', '@pop'],
 | 
			
		||||
                [/'/, 'string'],
 | 
			
		||||
                [/".*?"/, 'string'],
 | 
			
		||||
                [/'.*?'/, 'string'],
 | 
			
		||||
                [/[{}]/, 'delimiter'],
 | 
			
		||||
                [/[<>]/, 'operator'],
 | 
			
		||||
                [new RegExp(`\\b(${datatypePattern})\\b`, 'i'), 'type'], // Added 'i' flag for case-insensitive matching
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -5,45 +5,27 @@ import {
 | 
			
		||||
    PopoverTrigger,
 | 
			
		||||
} from '@/components/popover/popover';
 | 
			
		||||
import { colorOptions } from '@/lib/colors';
 | 
			
		||||
import { cn } from '@/lib/utils';
 | 
			
		||||
 | 
			
		||||
export interface ColorPickerProps {
 | 
			
		||||
    color: string;
 | 
			
		||||
    onChange: (color: string) => void;
 | 
			
		||||
    disabled?: boolean;
 | 
			
		||||
    popoverOnMouseDown?: (e: React.MouseEvent) => void;
 | 
			
		||||
    popoverOnClick?: (e: React.MouseEvent) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ColorPicker = React.forwardRef<
 | 
			
		||||
    React.ElementRef<typeof PopoverTrigger>,
 | 
			
		||||
    ColorPickerProps
 | 
			
		||||
>(({ color, onChange, disabled, popoverOnMouseDown, popoverOnClick }, ref) => {
 | 
			
		||||
>(({ color, onChange }, ref) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <Popover>
 | 
			
		||||
            <PopoverTrigger
 | 
			
		||||
                asChild
 | 
			
		||||
                ref={ref}
 | 
			
		||||
                disabled={disabled}
 | 
			
		||||
                {...(disabled ? { onClick: (e) => e.preventDefault() } : {})}
 | 
			
		||||
            >
 | 
			
		||||
            <PopoverTrigger asChild ref={ref}>
 | 
			
		||||
                <div
 | 
			
		||||
                    className={cn(
 | 
			
		||||
                        'h-6 w-8 cursor-pointer rounded-md border-2 border-muted transition-shadow hover:shadow-md',
 | 
			
		||||
                        {
 | 
			
		||||
                            'hover:shadow-none cursor-default': disabled,
 | 
			
		||||
                        }
 | 
			
		||||
                    )}
 | 
			
		||||
                    className="h-6 w-8 cursor-pointer rounded-md border-2 border-muted transition-shadow hover:shadow-md"
 | 
			
		||||
                    style={{
 | 
			
		||||
                        backgroundColor: color,
 | 
			
		||||
                    }}
 | 
			
		||||
                />
 | 
			
		||||
            </PopoverTrigger>
 | 
			
		||||
            <PopoverContent
 | 
			
		||||
                className="w-fit"
 | 
			
		||||
                onMouseDown={popoverOnMouseDown}
 | 
			
		||||
                onClick={popoverOnClick}
 | 
			
		||||
            >
 | 
			
		||||
            <PopoverContent className="w-fit">
 | 
			
		||||
                <div className="grid grid-cols-4 gap-2">
 | 
			
		||||
                    {colorOptions.map((option) => (
 | 
			
		||||
                        <div
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ import { Cross2Icon } from '@radix-ui/react-icons';
 | 
			
		||||
 | 
			
		||||
import { cn } from '@/lib/utils';
 | 
			
		||||
import { ScrollArea } from '../scroll-area/scroll-area';
 | 
			
		||||
import { ChevronLeft } from 'lucide-react';
 | 
			
		||||
 | 
			
		||||
const Dialog = DialogPrimitive.Root;
 | 
			
		||||
 | 
			
		||||
@@ -33,75 +32,28 @@ const DialogContent = React.forwardRef<
 | 
			
		||||
    React.ElementRef<typeof DialogPrimitive.Content>,
 | 
			
		||||
    React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
 | 
			
		||||
        showClose?: boolean;
 | 
			
		||||
        showBack?: boolean;
 | 
			
		||||
        backButtonClassName?: string;
 | 
			
		||||
        blurBackground?: boolean;
 | 
			
		||||
        forceOverlay?: boolean;
 | 
			
		||||
        onBackClick?: () => void;
 | 
			
		||||
    }
 | 
			
		||||
>(
 | 
			
		||||
    (
 | 
			
		||||
        {
 | 
			
		||||
            className,
 | 
			
		||||
            children,
 | 
			
		||||
            showClose,
 | 
			
		||||
            showBack,
 | 
			
		||||
            onBackClick,
 | 
			
		||||
            backButtonClassName,
 | 
			
		||||
            blurBackground,
 | 
			
		||||
            forceOverlay,
 | 
			
		||||
            ...props
 | 
			
		||||
        },
 | 
			
		||||
        ref
 | 
			
		||||
    ) => (
 | 
			
		||||
        <DialogPortal>
 | 
			
		||||
            {forceOverlay ? (
 | 
			
		||||
                <div
 | 
			
		||||
                    className={cn(
 | 
			
		||||
                        'fixed inset-0 z-50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
 | 
			
		||||
                        {
 | 
			
		||||
                            'bg-black/80': !blurBackground,
 | 
			
		||||
                            'bg-black/30 backdrop-blur-sm': blurBackground,
 | 
			
		||||
                        }
 | 
			
		||||
                    )}
 | 
			
		||||
                    data-state="open"
 | 
			
		||||
                />
 | 
			
		||||
            ) : null}
 | 
			
		||||
            <DialogOverlay
 | 
			
		||||
                className={cn({
 | 
			
		||||
                    'bg-black/30 backdrop-blur-sm': blurBackground,
 | 
			
		||||
                })}
 | 
			
		||||
            />
 | 
			
		||||
            <DialogPrimitive.Content
 | 
			
		||||
                ref={ref}
 | 
			
		||||
                className={cn(
 | 
			
		||||
                    'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
 | 
			
		||||
                    className
 | 
			
		||||
                )}
 | 
			
		||||
                {...props}
 | 
			
		||||
            >
 | 
			
		||||
                {children}
 | 
			
		||||
                {showBack && (
 | 
			
		||||
                    <button
 | 
			
		||||
                        onClick={() => onBackClick?.()}
 | 
			
		||||
                        className={cn(
 | 
			
		||||
                            'absolute left-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground',
 | 
			
		||||
                            backButtonClassName
 | 
			
		||||
                        )}
 | 
			
		||||
                    >
 | 
			
		||||
                        <ChevronLeft className="size-4" />
 | 
			
		||||
                    </button>
 | 
			
		||||
                )}
 | 
			
		||||
                {showClose && (
 | 
			
		||||
                    <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
 | 
			
		||||
                        <Cross2Icon className="size-4" />
 | 
			
		||||
                        <span className="sr-only">Close</span>
 | 
			
		||||
                    </DialogPrimitive.Close>
 | 
			
		||||
                )}
 | 
			
		||||
            </DialogPrimitive.Content>
 | 
			
		||||
        </DialogPortal>
 | 
			
		||||
    )
 | 
			
		||||
);
 | 
			
		||||
>(({ className, children, showClose, ...props }, ref) => (
 | 
			
		||||
    <DialogPortal>
 | 
			
		||||
        <DialogOverlay />
 | 
			
		||||
        <DialogPrimitive.Content
 | 
			
		||||
            ref={ref}
 | 
			
		||||
            className={cn(
 | 
			
		||||
                'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
        >
 | 
			
		||||
            {children}
 | 
			
		||||
            {showClose && (
 | 
			
		||||
                <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
 | 
			
		||||
                    <Cross2Icon className="size-4" />
 | 
			
		||||
                    <span className="sr-only">Close</span>
 | 
			
		||||
                </DialogPrimitive.Close>
 | 
			
		||||
            )}
 | 
			
		||||
        </DialogPrimitive.Content>
 | 
			
		||||
    </DialogPortal>
 | 
			
		||||
));
 | 
			
		||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
 | 
			
		||||
 | 
			
		||||
const DialogHeader = ({
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,9 @@
 | 
			
		||||
import React, { forwardRef } from 'react';
 | 
			
		||||
import EmptyStateImage from '@/assets/empty_state.png';
 | 
			
		||||
import EmptyStateImageDark from '@/assets/empty_state_dark.png';
 | 
			
		||||
import { Label } from '@/components/label/label';
 | 
			
		||||
import { cn } from '@/lib/utils';
 | 
			
		||||
import { useTheme } from '@/hooks/use-theme';
 | 
			
		||||
import {
 | 
			
		||||
    Empty,
 | 
			
		||||
    EmptyContent,
 | 
			
		||||
    EmptyDescription,
 | 
			
		||||
    EmptyHeader,
 | 
			
		||||
    EmptyMedia,
 | 
			
		||||
    EmptyTitle,
 | 
			
		||||
} from '../empty/empty';
 | 
			
		||||
 | 
			
		||||
export interface EmptyStateProps {
 | 
			
		||||
    title: string;
 | 
			
		||||
@@ -45,29 +38,26 @@ export const EmptyState = forwardRef<
 | 
			
		||||
                    className
 | 
			
		||||
                )}
 | 
			
		||||
            >
 | 
			
		||||
                <Empty>
 | 
			
		||||
                    <EmptyHeader>
 | 
			
		||||
                        <EmptyMedia variant="icon">
 | 
			
		||||
                            {/* <Group /> */}
 | 
			
		||||
                            <img
 | 
			
		||||
                                src={
 | 
			
		||||
                                    effectiveTheme === 'dark'
 | 
			
		||||
                                        ? EmptyStateImageDark
 | 
			
		||||
                                        : EmptyStateImage
 | 
			
		||||
                                }
 | 
			
		||||
                                alt="Empty state"
 | 
			
		||||
                                className={cn('p-2', imageClassName)}
 | 
			
		||||
                            />
 | 
			
		||||
                        </EmptyMedia>
 | 
			
		||||
                        <EmptyTitle className={titleClassName}>
 | 
			
		||||
                            {title}
 | 
			
		||||
                        </EmptyTitle>
 | 
			
		||||
                        <EmptyDescription className={descriptionClassName}>
 | 
			
		||||
                            {description}
 | 
			
		||||
                        </EmptyDescription>
 | 
			
		||||
                    </EmptyHeader>
 | 
			
		||||
                    <EmptyContent />
 | 
			
		||||
                </Empty>
 | 
			
		||||
                <img
 | 
			
		||||
                    src={
 | 
			
		||||
                        effectiveTheme === 'dark'
 | 
			
		||||
                            ? EmptyStateImageDark
 | 
			
		||||
                            : EmptyStateImage
 | 
			
		||||
                    }
 | 
			
		||||
                    alt="Empty state"
 | 
			
		||||
                    className={cn('mb-2 w-20', imageClassName)}
 | 
			
		||||
                />
 | 
			
		||||
                <Label className={cn('text-base', titleClassName)}>
 | 
			
		||||
                    {title}
 | 
			
		||||
                </Label>
 | 
			
		||||
                <Label
 | 
			
		||||
                    className={cn(
 | 
			
		||||
                        'text-sm text-center font-normal text-muted-foreground',
 | 
			
		||||
                        descriptionClassName
 | 
			
		||||
                    )}
 | 
			
		||||
                >
 | 
			
		||||
                    {description}
 | 
			
		||||
                </Label>
 | 
			
		||||
            </div>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,105 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { cva, type VariantProps } from 'class-variance-authority';
 | 
			
		||||
 | 
			
		||||
import { cn } from '@/lib/utils/index';
 | 
			
		||||
 | 
			
		||||
function Empty({ className, ...props }: React.ComponentProps<'div'>) {
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            data-slot="empty"
 | 
			
		||||
            className={cn(
 | 
			
		||||
                'flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function EmptyHeader({ className, ...props }: React.ComponentProps<'div'>) {
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            data-slot="empty-header"
 | 
			
		||||
            className={cn(
 | 
			
		||||
                'flex max-w-sm flex-col items-center gap-2 text-center',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const emptyMediaVariants = cva(
 | 
			
		||||
    'mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
 | 
			
		||||
    {
 | 
			
		||||
        variants: {
 | 
			
		||||
            variant: {
 | 
			
		||||
                default: 'bg-transparent',
 | 
			
		||||
                icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6",
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        defaultVariants: {
 | 
			
		||||
            variant: 'default',
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
function EmptyMedia({
 | 
			
		||||
    className,
 | 
			
		||||
    variant = 'default',
 | 
			
		||||
    ...props
 | 
			
		||||
}: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>) {
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            data-slot="empty-icon"
 | 
			
		||||
            data-variant={variant}
 | 
			
		||||
            className={cn(emptyMediaVariants({ variant, className }))}
 | 
			
		||||
            {...props}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function EmptyTitle({ className, ...props }: React.ComponentProps<'div'>) {
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            data-slot="empty-title"
 | 
			
		||||
            className={cn('text-lg font-medium tracking-tight', className)}
 | 
			
		||||
            {...props}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            data-slot="empty-description"
 | 
			
		||||
            className={cn(
 | 
			
		||||
                'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function EmptyContent({ className, ...props }: React.ComponentProps<'div'>) {
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            data-slot="empty-content"
 | 
			
		||||
            className={cn(
 | 
			
		||||
                'flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
    Empty,
 | 
			
		||||
    EmptyHeader,
 | 
			
		||||
    EmptyTitle,
 | 
			
		||||
    EmptyDescription,
 | 
			
		||||
    EmptyContent,
 | 
			
		||||
    EmptyMedia,
 | 
			
		||||
};
 | 
			
		||||
@@ -2,13 +2,16 @@ import React from 'react';
 | 
			
		||||
 | 
			
		||||
import { cn } from '@/lib/utils';
 | 
			
		||||
 | 
			
		||||
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
 | 
			
		||||
export interface InputProps
 | 
			
		||||
    extends React.InputHTMLAttributes<HTMLInputElement> {}
 | 
			
		||||
 | 
			
		||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
 | 
			
		||||
    ({ className, type, ...props }, ref) => {
 | 
			
		||||
        return (
 | 
			
		||||
            <input
 | 
			
		||||
                type={type}
 | 
			
		||||
                className={cn(
 | 
			
		||||
                    'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
 | 
			
		||||
                    'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
 | 
			
		||||
                    className
 | 
			
		||||
                )}
 | 
			
		||||
                ref={ref}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,6 @@ export interface SelectBoxOption {
 | 
			
		||||
    regex?: string;
 | 
			
		||||
    extractRegex?: RegExp;
 | 
			
		||||
    group?: string;
 | 
			
		||||
    icon?: React.ReactNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SelectBoxProps {
 | 
			
		||||
@@ -54,11 +53,6 @@ export interface SelectBoxProps {
 | 
			
		||||
    open?: boolean;
 | 
			
		||||
    onOpenChange?: (open: boolean) => void;
 | 
			
		||||
    popoverClassName?: string;
 | 
			
		||||
    readonly?: boolean;
 | 
			
		||||
    footerButtons?: React.ReactNode;
 | 
			
		||||
    commandOnMouseDown?: (e: React.MouseEvent) => void;
 | 
			
		||||
    commandOnClick?: (e: React.MouseEvent) => void;
 | 
			
		||||
    onSearchChange?: (search: string) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
@@ -84,11 +78,6 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
            open,
 | 
			
		||||
            onOpenChange: setOpen,
 | 
			
		||||
            popoverClassName,
 | 
			
		||||
            readonly,
 | 
			
		||||
            footerButtons,
 | 
			
		||||
            commandOnMouseDown,
 | 
			
		||||
            commandOnClick,
 | 
			
		||||
            onSearchChange,
 | 
			
		||||
        },
 | 
			
		||||
        ref
 | 
			
		||||
    ) => {
 | 
			
		||||
@@ -104,12 +93,6 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
            (isOpen: boolean) => {
 | 
			
		||||
                setOpen?.(isOpen);
 | 
			
		||||
                setIsOpen(isOpen);
 | 
			
		||||
 | 
			
		||||
                if (isOpen) {
 | 
			
		||||
                    setSearchTerm('');
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                setTimeout(() => (document.body.style.pointerEvents = ''), 500);
 | 
			
		||||
            },
 | 
			
		||||
            [setOpen]
 | 
			
		||||
        );
 | 
			
		||||
@@ -163,20 +146,18 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
                            className={`inline-flex min-w-0 shrink-0 items-center gap-1 rounded-md border py-0.5 pl-2 pr-1 text-xs font-medium text-foreground transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 ${oneLine ? 'mx-0.5' : ''}`}
 | 
			
		||||
                        >
 | 
			
		||||
                            <span>{option.label}</span>
 | 
			
		||||
                            {!readonly ? (
 | 
			
		||||
                                <span
 | 
			
		||||
                                    onClick={(e) => {
 | 
			
		||||
                                        e.preventDefault();
 | 
			
		||||
                                        handleSelect(option.value);
 | 
			
		||||
                                    }}
 | 
			
		||||
                                    className="flex items-center rounded-sm px-px text-muted-foreground/60 hover:bg-accent hover:text-muted-foreground"
 | 
			
		||||
                                >
 | 
			
		||||
                                    <Cross2Icon />
 | 
			
		||||
                                </span>
 | 
			
		||||
                            ) : null}
 | 
			
		||||
                            <span
 | 
			
		||||
                                onClick={(e) => {
 | 
			
		||||
                                    e.preventDefault();
 | 
			
		||||
                                    handleSelect(option.value);
 | 
			
		||||
                                }}
 | 
			
		||||
                                className="flex items-center rounded-sm px-px text-muted-foreground/60 hover:bg-accent hover:text-muted-foreground"
 | 
			
		||||
                            >
 | 
			
		||||
                                <Cross2Icon />
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </span>
 | 
			
		||||
                    )),
 | 
			
		||||
            [options, value, handleSelect, oneLine, keepOrder, readonly]
 | 
			
		||||
            [options, value, handleSelect, oneLine, keepOrder]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const isAllSelected = React.useMemo(
 | 
			
		||||
@@ -242,16 +223,13 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
                    <CommandItem
 | 
			
		||||
                        className="flex items-center"
 | 
			
		||||
                        key={option.value}
 | 
			
		||||
                        value={option.label}
 | 
			
		||||
                        keywords={option.regex ? [option.regex] : undefined}
 | 
			
		||||
                        onSelect={() =>
 | 
			
		||||
                            handleSelect(
 | 
			
		||||
                                option.value,
 | 
			
		||||
                                matches?.map((match) => match?.toString())
 | 
			
		||||
                                matches?.map((match) => match.toString())
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                        onMouseDown={commandOnMouseDown}
 | 
			
		||||
                        onClick={commandOnClick}
 | 
			
		||||
                    >
 | 
			
		||||
                        {multiple && (
 | 
			
		||||
                            <div
 | 
			
		||||
@@ -266,11 +244,6 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
                            </div>
 | 
			
		||||
                        )}
 | 
			
		||||
                        <div className="flex flex-1 items-center truncate">
 | 
			
		||||
                            {option.icon ? (
 | 
			
		||||
                                <span className="mr-2 shrink-0">
 | 
			
		||||
                                    {option.icon}
 | 
			
		||||
                                </span>
 | 
			
		||||
                            ) : null}
 | 
			
		||||
                            <span>
 | 
			
		||||
                                {isRegexMatch ? searchTerm : option.label}
 | 
			
		||||
                                {!isRegexMatch && optionSuffix
 | 
			
		||||
@@ -297,15 +270,7 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
                    </CommandItem>
 | 
			
		||||
                );
 | 
			
		||||
            },
 | 
			
		||||
            [
 | 
			
		||||
                value,
 | 
			
		||||
                multiple,
 | 
			
		||||
                searchTerm,
 | 
			
		||||
                handleSelect,
 | 
			
		||||
                optionSuffix,
 | 
			
		||||
                commandOnClick,
 | 
			
		||||
                commandOnMouseDown,
 | 
			
		||||
            ]
 | 
			
		||||
            [value, multiple, searchTerm, handleSelect, optionSuffix]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
@@ -313,7 +278,7 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
                <PopoverTrigger asChild tabIndex={0} onKeyDown={handleKeyDown}>
 | 
			
		||||
                    <div
 | 
			
		||||
                        className={cn(
 | 
			
		||||
                            `flex min-h-[36px] cursor-pointer items-center justify-between rounded-md border px-3 py-1 data-[state=open]:border-ring ${disabled ? 'bg-muted pointer-events-none' : ''} ${readonly ? 'pointer-events-none' : ''}`,
 | 
			
		||||
                            `flex min-h-[36px] cursor-pointer items-center justify-between rounded-md border px-3 py-1 data-[state=open]:border-ring ${disabled ? 'bg-muted pointer-events-none' : ''}`,
 | 
			
		||||
                            className
 | 
			
		||||
                        )}
 | 
			
		||||
                    >
 | 
			
		||||
@@ -383,8 +348,6 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
                        popoverClassName
 | 
			
		||||
                    )}
 | 
			
		||||
                    align="center"
 | 
			
		||||
                    onMouseDown={(e) => e.stopPropagation()}
 | 
			
		||||
                    onClick={(e) => e.stopPropagation()}
 | 
			
		||||
                >
 | 
			
		||||
                    <Command
 | 
			
		||||
                        filter={(value, search, keywords) => {
 | 
			
		||||
@@ -407,10 +370,7 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
                        <div className="relative">
 | 
			
		||||
                            <CommandInput
 | 
			
		||||
                                value={searchTerm}
 | 
			
		||||
                                onValueChange={(e) => {
 | 
			
		||||
                                    setSearchTerm(e);
 | 
			
		||||
                                    onSearchChange?.(e);
 | 
			
		||||
                                }}
 | 
			
		||||
                                onValueChange={(e) => setSearchTerm(e)}
 | 
			
		||||
                                ref={ref}
 | 
			
		||||
                                placeholder={inputPlaceholder ?? 'Search...'}
 | 
			
		||||
                                className="h-9"
 | 
			
		||||
@@ -477,9 +437,6 @@ export const SelectBox = React.forwardRef<HTMLInputElement, SelectBoxProps>(
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </ScrollArea>
 | 
			
		||||
                    </Command>
 | 
			
		||||
                    {footerButtons ? (
 | 
			
		||||
                        <div className="border-t">{footerButtons}</div>
 | 
			
		||||
                    ) : null}
 | 
			
		||||
                </PopoverContent>
 | 
			
		||||
            </Popover>
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,6 @@ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
 | 
			
		||||
const SIDEBAR_WIDTH = '16rem';
 | 
			
		||||
const SIDEBAR_WIDTH_MOBILE = '18rem';
 | 
			
		||||
const SIDEBAR_WIDTH_ICON = '3rem';
 | 
			
		||||
const SIDEBAR_WIDTH_ICON_EXTENDED = '4rem';
 | 
			
		||||
const SIDEBAR_KEYBOARD_SHORTCUT = 'b';
 | 
			
		||||
 | 
			
		||||
type SidebarContext = {
 | 
			
		||||
@@ -143,8 +142,6 @@ const SidebarProvider = React.forwardRef<
 | 
			
		||||
                            {
 | 
			
		||||
                                '--sidebar-width': SIDEBAR_WIDTH,
 | 
			
		||||
                                '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
 | 
			
		||||
                                '--sidebar-width-icon-extended':
 | 
			
		||||
                                    SIDEBAR_WIDTH_ICON_EXTENDED,
 | 
			
		||||
                                ...style,
 | 
			
		||||
                            } as React.CSSProperties
 | 
			
		||||
                        }
 | 
			
		||||
@@ -169,7 +166,7 @@ const Sidebar = React.forwardRef<
 | 
			
		||||
    React.ComponentProps<'div'> & {
 | 
			
		||||
        side?: 'left' | 'right';
 | 
			
		||||
        variant?: 'sidebar' | 'floating' | 'inset';
 | 
			
		||||
        collapsible?: 'offcanvas' | 'icon' | 'icon-extended' | 'none';
 | 
			
		||||
        collapsible?: 'offcanvas' | 'icon' | 'none';
 | 
			
		||||
    }
 | 
			
		||||
>(
 | 
			
		||||
    (
 | 
			
		||||
@@ -248,8 +245,8 @@ const Sidebar = React.forwardRef<
 | 
			
		||||
                        'group-data-[collapsible=offcanvas]:w-0',
 | 
			
		||||
                        'group-data-[side=right]:rotate-180',
 | 
			
		||||
                        variant === 'floating' || variant === 'inset'
 | 
			
		||||
                            ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))] group-data-[collapsible=icon-extended]:w-[calc(var(--sidebar-width-icon-extended)_+_theme(spacing.4))]'
 | 
			
		||||
                            : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[collapsible=icon-extended]:w-[--sidebar-width-icon-extended]'
 | 
			
		||||
                            ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'
 | 
			
		||||
                            : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]'
 | 
			
		||||
                    )}
 | 
			
		||||
                />
 | 
			
		||||
                <div
 | 
			
		||||
@@ -260,8 +257,8 @@ const Sidebar = React.forwardRef<
 | 
			
		||||
                            : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
 | 
			
		||||
                        // Adjust the padding for floating and inset variants.
 | 
			
		||||
                        variant === 'floating' || variant === 'inset'
 | 
			
		||||
                            ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)] group-data-[collapsible=icon-extended]:w-[calc(var(--sidebar-width-icon-extended)_+_theme(spacing.4)_+2px)]'
 | 
			
		||||
                            : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[collapsible=icon-extended]:w-[--sidebar-width-icon-extended] group-data-[side=left]:border-r group-data-[side=right]:border-l',
 | 
			
		||||
                            ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'
 | 
			
		||||
                            : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',
 | 
			
		||||
                        className
 | 
			
		||||
                    )}
 | 
			
		||||
                    {...props}
 | 
			
		||||
@@ -424,7 +421,7 @@ const SidebarContent = React.forwardRef<
 | 
			
		||||
            ref={ref}
 | 
			
		||||
            data-sidebar="content"
 | 
			
		||||
            className={cn(
 | 
			
		||||
                'flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden group-data-[collapsible=icon-extended]:overflow-hidden',
 | 
			
		||||
                'flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
@@ -464,7 +461,6 @@ const SidebarGroupLabel = React.forwardRef<
 | 
			
		||||
            className={cn(
 | 
			
		||||
                'flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
 | 
			
		||||
                'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
 | 
			
		||||
                'group-data-[collapsible=icon-extended]:-mt-8 group-data-[collapsible=icon-extended]:opacity-0',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
@@ -487,7 +483,7 @@ const SidebarGroupAction = React.forwardRef<
 | 
			
		||||
                'absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
 | 
			
		||||
                // Increases the hit area of the button on mobile.
 | 
			
		||||
                'after:absolute after:-inset-2 after:md:hidden',
 | 
			
		||||
                'group-data-[collapsible=icon]:hidden group-data-[collapsible=icon-extended]:hidden',
 | 
			
		||||
                'group-data-[collapsible=icon]:hidden',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
@@ -536,7 +532,7 @@ const SidebarMenuItem = React.forwardRef<
 | 
			
		||||
SidebarMenuItem.displayName = 'SidebarMenuItem';
 | 
			
		||||
 | 
			
		||||
const sidebarMenuButtonVariants = cva(
 | 
			
		||||
    'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon-extended]:h-auto group-data-[collapsible=icon-extended]:flex-col group-data-[collapsible=icon-extended]:gap-1 group-data-[collapsible=icon-extended]:p-2 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate group-data-[collapsible=icon-extended]:[&>span]:w-full group-data-[collapsible=icon-extended]:[&>span]:text-center group-data-[collapsible=icon-extended]:[&>span]:text-[10px] group-data-[collapsible=icon-extended]:[&>span]:leading-tight [&>svg]:size-4 [&>svg]:shrink-0',
 | 
			
		||||
    'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
 | 
			
		||||
    {
 | 
			
		||||
        variants: {
 | 
			
		||||
            variant: {
 | 
			
		||||
@@ -640,7 +636,7 @@ const SidebarMenuAction = React.forwardRef<
 | 
			
		||||
                'peer-data-[size=sm]/menu-button:top-1',
 | 
			
		||||
                'peer-data-[size=default]/menu-button:top-1.5',
 | 
			
		||||
                'peer-data-[size=lg]/menu-button:top-2.5',
 | 
			
		||||
                'group-data-[collapsible=icon]:hidden group-data-[collapsible=icon-extended]:hidden',
 | 
			
		||||
                'group-data-[collapsible=icon]:hidden',
 | 
			
		||||
                showOnHover &&
 | 
			
		||||
                    'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0',
 | 
			
		||||
                className
 | 
			
		||||
@@ -757,7 +753,7 @@ const SidebarMenuSubButton = React.forwardRef<
 | 
			
		||||
                'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
 | 
			
		||||
                size === 'sm' && 'text-xs',
 | 
			
		||||
                size === 'md' && 'text-sm',
 | 
			
		||||
                'group-data-[collapsible=icon]:hidden group-data-[collapsible=icon-extended]:hidden',
 | 
			
		||||
                'group-data-[collapsible=icon]:hidden',
 | 
			
		||||
                className
 | 
			
		||||
            )}
 | 
			
		||||
            {...props}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,17 +13,15 @@ const TooltipContent = React.forwardRef<
 | 
			
		||||
    React.ElementRef<typeof TooltipPrimitive.Content>,
 | 
			
		||||
    React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
 | 
			
		||||
>(({ className, sideOffset = 4, ...props }, ref) => (
 | 
			
		||||
    // <TooltipPrimitive.Portal>
 | 
			
		||||
    <TooltipPrimitive.Content
 | 
			
		||||
        ref={ref}
 | 
			
		||||
        sideOffset={sideOffset}
 | 
			
		||||
        className={cn(
 | 
			
		||||
            'z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]',
 | 
			
		||||
            'z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
 | 
			
		||||
            className
 | 
			
		||||
        )}
 | 
			
		||||
        {...props}
 | 
			
		||||
    />
 | 
			
		||||
    // </TooltipPrimitive.Portal>
 | 
			
		||||
));
 | 
			
		||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,6 @@ interface TreeViewProps<
 | 
			
		||||
    renderHoverComponent?: (node: TreeNode<Type, Context>) => ReactNode;
 | 
			
		||||
    renderActionsComponent?: (node: TreeNode<Type, Context>) => ReactNode;
 | 
			
		||||
    loadingNodeIds?: string[];
 | 
			
		||||
    disableCache?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function TreeView<
 | 
			
		||||
@@ -63,14 +62,12 @@ export function TreeView<
 | 
			
		||||
    renderHoverComponent,
 | 
			
		||||
    renderActionsComponent,
 | 
			
		||||
    loadingNodeIds,
 | 
			
		||||
    disableCache = false,
 | 
			
		||||
}: TreeViewProps<Type, Context>) {
 | 
			
		||||
    const { expanded, loading, loadedChildren, hasMoreChildren, toggleNode } =
 | 
			
		||||
        useTree({
 | 
			
		||||
            fetchChildren,
 | 
			
		||||
            expanded: expandedProp,
 | 
			
		||||
            setExpanded: setExpandedProp,
 | 
			
		||||
            disableCache,
 | 
			
		||||
        });
 | 
			
		||||
    const [selectedIdInternal, setSelectedIdInternal] = React.useState<
 | 
			
		||||
        string | undefined
 | 
			
		||||
@@ -148,7 +145,6 @@ export function TreeView<
 | 
			
		||||
                    renderHoverComponent={renderHoverComponent}
 | 
			
		||||
                    renderActionsComponent={renderActionsComponent}
 | 
			
		||||
                    loadingNodeIds={loadingNodeIds}
 | 
			
		||||
                    disableCache={disableCache}
 | 
			
		||||
                />
 | 
			
		||||
            ))}
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -183,7 +179,6 @@ interface TreeNodeProps<
 | 
			
		||||
    renderHoverComponent?: (node: TreeNode<Type, Context>) => ReactNode;
 | 
			
		||||
    renderActionsComponent?: (node: TreeNode<Type, Context>) => ReactNode;
 | 
			
		||||
    loadingNodeIds?: string[];
 | 
			
		||||
    disableCache?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function TreeNode<Type extends string, Context extends Record<Type, unknown>>({
 | 
			
		||||
@@ -206,16 +201,11 @@ function TreeNode<Type extends string, Context extends Record<Type, unknown>>({
 | 
			
		||||
    renderHoverComponent,
 | 
			
		||||
    renderActionsComponent,
 | 
			
		||||
    loadingNodeIds,
 | 
			
		||||
    disableCache = false,
 | 
			
		||||
}: TreeNodeProps<Type, Context>) {
 | 
			
		||||
    const [isHovered, setIsHovered] = useState(false);
 | 
			
		||||
    const isExpanded = expanded[node.id];
 | 
			
		||||
    const isLoading = loading[node.id];
 | 
			
		||||
    // If cache is disabled, always use fresh node.children
 | 
			
		||||
    // Otherwise, use cached loadedChildren if available (for async fetched data)
 | 
			
		||||
    const children = disableCache
 | 
			
		||||
        ? node.children
 | 
			
		||||
        : node.children || loadedChildren[node.id];
 | 
			
		||||
    const children = loadedChildren[node.id] || node.children;
 | 
			
		||||
    const isSelected = selectedId === node.id;
 | 
			
		||||
 | 
			
		||||
    const IconComponent =
 | 
			
		||||
@@ -433,7 +423,6 @@ function TreeNode<Type extends string, Context extends Record<Type, unknown>>({
 | 
			
		||||
                                renderHoverComponent={renderHoverComponent}
 | 
			
		||||
                                renderActionsComponent={renderActionsComponent}
 | 
			
		||||
                                loadingNodeIds={loadingNodeIds}
 | 
			
		||||
                                disableCache={disableCache}
 | 
			
		||||
                            />
 | 
			
		||||
                        ))}
 | 
			
		||||
                        {isLoading ? (
 | 
			
		||||
 
 | 
			
		||||
@@ -28,12 +28,10 @@ export function useTree<
 | 
			
		||||
    fetchChildren,
 | 
			
		||||
    expanded: expandedProp,
 | 
			
		||||
    setExpanded: setExpandedProp,
 | 
			
		||||
    disableCache = false,
 | 
			
		||||
}: {
 | 
			
		||||
    fetchChildren?: FetchChildrenFunction<Type, Context>;
 | 
			
		||||
    expanded?: ExpandedState;
 | 
			
		||||
    setExpanded?: Dispatch<SetStateAction<ExpandedState>>;
 | 
			
		||||
    disableCache?: boolean;
 | 
			
		||||
}) {
 | 
			
		||||
    const [expandedInternal, setExpandedInternal] = useState<ExpandedState>({});
 | 
			
		||||
 | 
			
		||||
@@ -91,8 +89,8 @@ export function useTree<
 | 
			
		||||
            // Get any previously fetched children
 | 
			
		||||
            const previouslyFetchedChildren = loadedChildren[nodeId] || [];
 | 
			
		||||
 | 
			
		||||
            // Only cache if caching is enabled
 | 
			
		||||
            if (!disableCache && staticChildren?.length) {
 | 
			
		||||
            // If we have static children, merge them with any previously fetched children
 | 
			
		||||
            if (staticChildren?.length) {
 | 
			
		||||
                const mergedChildren = mergeChildren(
 | 
			
		||||
                    staticChildren,
 | 
			
		||||
                    previouslyFetchedChildren
 | 
			
		||||
@@ -112,8 +110,8 @@ export function useTree<
 | 
			
		||||
            // Set expanded state immediately to show static/previously fetched children
 | 
			
		||||
            setExpanded((prev) => ({ ...prev, [nodeId]: true }));
 | 
			
		||||
 | 
			
		||||
            // If we haven't loaded dynamic children yet and cache is enabled
 | 
			
		||||
            if (!disableCache && !previouslyFetchedChildren.length) {
 | 
			
		||||
            // If we haven't loaded dynamic children yet
 | 
			
		||||
            if (!previouslyFetchedChildren.length) {
 | 
			
		||||
                setLoading((prev) => ({ ...prev, [nodeId]: true }));
 | 
			
		||||
                try {
 | 
			
		||||
                    const fetchedChildren = await fetchChildren?.(
 | 
			
		||||
@@ -142,14 +140,7 @@ export function useTree<
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [
 | 
			
		||||
            expanded,
 | 
			
		||||
            loadedChildren,
 | 
			
		||||
            fetchChildren,
 | 
			
		||||
            mergeChildren,
 | 
			
		||||
            setExpanded,
 | 
			
		||||
            disableCache,
 | 
			
		||||
        ]
 | 
			
		||||
        [expanded, loadedChildren, fetchChildren, mergeChildren, setExpanded]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,24 +2,6 @@ import { createContext } from 'react';
 | 
			
		||||
import { emptyFn } from '@/lib/utils';
 | 
			
		||||
import type { Graph } from '@/lib/graph';
 | 
			
		||||
import { createGraph } from '@/lib/graph';
 | 
			
		||||
import { EventEmitter } from 'ahooks/lib/useEventEmitter';
 | 
			
		||||
 | 
			
		||||
export type CanvasEventType = 'pan_click';
 | 
			
		||||
 | 
			
		||||
export type CanvasEventBase<T extends CanvasEventType, D> = {
 | 
			
		||||
    action: T;
 | 
			
		||||
    data: D;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type PanClickEvent = CanvasEventBase<
 | 
			
		||||
    'pan_click',
 | 
			
		||||
    {
 | 
			
		||||
        x: number;
 | 
			
		||||
        y: number;
 | 
			
		||||
    }
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
export type CanvasEvent = PanClickEvent;
 | 
			
		||||
 | 
			
		||||
export interface CanvasContext {
 | 
			
		||||
    reorderTables: (options?: { updateHistory?: boolean }) => void;
 | 
			
		||||
@@ -32,42 +14,6 @@ export interface CanvasContext {
 | 
			
		||||
    overlapGraph: Graph<string>;
 | 
			
		||||
    setShowFilter: React.Dispatch<React.SetStateAction<boolean>>;
 | 
			
		||||
    showFilter: boolean;
 | 
			
		||||
    editTableModeTable: {
 | 
			
		||||
        tableId: string;
 | 
			
		||||
        fieldId?: string;
 | 
			
		||||
    } | null;
 | 
			
		||||
    setEditTableModeTable: React.Dispatch<
 | 
			
		||||
        React.SetStateAction<{
 | 
			
		||||
            tableId: string;
 | 
			
		||||
            fieldId?: string;
 | 
			
		||||
        } | null>
 | 
			
		||||
    >;
 | 
			
		||||
    tempFloatingEdge: {
 | 
			
		||||
        sourceNodeId: string;
 | 
			
		||||
        targetNodeId?: string;
 | 
			
		||||
    } | null;
 | 
			
		||||
    setTempFloatingEdge: React.Dispatch<
 | 
			
		||||
        React.SetStateAction<{
 | 
			
		||||
            sourceNodeId: string;
 | 
			
		||||
            targetNodeId?: string;
 | 
			
		||||
        } | null>
 | 
			
		||||
    >;
 | 
			
		||||
    startFloatingEdgeCreation: ({
 | 
			
		||||
        sourceNodeId,
 | 
			
		||||
    }: {
 | 
			
		||||
        sourceNodeId: string;
 | 
			
		||||
    }) => void;
 | 
			
		||||
    endFloatingEdgeCreation: () => void;
 | 
			
		||||
    hoveringTableId: string | null;
 | 
			
		||||
    setHoveringTableId: React.Dispatch<React.SetStateAction<string | null>>;
 | 
			
		||||
    showCreateRelationshipNode: (params: {
 | 
			
		||||
        sourceTableId: string;
 | 
			
		||||
        targetTableId: string;
 | 
			
		||||
        x: number;
 | 
			
		||||
        y: number;
 | 
			
		||||
    }) => void;
 | 
			
		||||
    hideCreateRelationshipNode: () => void;
 | 
			
		||||
    events: EventEmitter<CanvasEvent>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const canvasContext = createContext<CanvasContext>({
 | 
			
		||||
@@ -77,15 +23,4 @@ export const canvasContext = createContext<CanvasContext>({
 | 
			
		||||
    overlapGraph: createGraph(),
 | 
			
		||||
    setShowFilter: emptyFn,
 | 
			
		||||
    showFilter: false,
 | 
			
		||||
    editTableModeTable: null,
 | 
			
		||||
    setEditTableModeTable: emptyFn,
 | 
			
		||||
    tempFloatingEdge: null,
 | 
			
		||||
    setTempFloatingEdge: emptyFn,
 | 
			
		||||
    startFloatingEdgeCreation: emptyFn,
 | 
			
		||||
    endFloatingEdgeCreation: emptyFn,
 | 
			
		||||
    hoveringTableId: null,
 | 
			
		||||
    setHoveringTableId: emptyFn,
 | 
			
		||||
    showCreateRelationshipNode: emptyFn,
 | 
			
		||||
    hideCreateRelationshipNode: emptyFn,
 | 
			
		||||
    events: new EventEmitter(),
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,74 +1,28 @@
 | 
			
		||||
import React, {
 | 
			
		||||
    type ReactNode,
 | 
			
		||||
    useCallback,
 | 
			
		||||
    useState,
 | 
			
		||||
    useEffect,
 | 
			
		||||
    useRef,
 | 
			
		||||
} from 'react';
 | 
			
		||||
import type { CanvasContext, CanvasEvent } from './canvas-context';
 | 
			
		||||
import React, { type ReactNode, useCallback, useState } from 'react';
 | 
			
		||||
import { canvasContext } from './canvas-context';
 | 
			
		||||
import { useChartDB } from '@/hooks/use-chartdb';
 | 
			
		||||
import { adjustTablePositions } from '@/lib/domain/db-table';
 | 
			
		||||
import {
 | 
			
		||||
    adjustTablePositions,
 | 
			
		||||
    shouldShowTablesBySchemaFilter,
 | 
			
		||||
} from '@/lib/domain/db-table';
 | 
			
		||||
import { useReactFlow } from '@xyflow/react';
 | 
			
		||||
import { findOverlappingTables } from '@/pages/editor-page/canvas/canvas-utils';
 | 
			
		||||
import type { Graph } from '@/lib/graph';
 | 
			
		||||
import { createGraph } from '@/lib/graph';
 | 
			
		||||
import { useDiagramFilter } from '../diagram-filter-context/use-diagram-filter';
 | 
			
		||||
import { filterTable } from '@/lib/domain/diagram-filter/filter';
 | 
			
		||||
import { defaultSchemas } from '@/lib/data/default-schemas';
 | 
			
		||||
import {
 | 
			
		||||
    CREATE_RELATIONSHIP_NODE_ID,
 | 
			
		||||
    type CreateRelationshipNodeType,
 | 
			
		||||
} from '@/pages/editor-page/canvas/create-relationship-node/create-relationship-node';
 | 
			
		||||
import { useEventEmitter } from 'ahooks';
 | 
			
		||||
 | 
			
		||||
interface CanvasProviderProps {
 | 
			
		||||
    children: ReactNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const CanvasProvider = ({ children }: CanvasProviderProps) => {
 | 
			
		||||
    const {
 | 
			
		||||
        tables,
 | 
			
		||||
        relationships,
 | 
			
		||||
        updateTablesState,
 | 
			
		||||
        databaseType,
 | 
			
		||||
        areas,
 | 
			
		||||
        diagramId,
 | 
			
		||||
    } = useChartDB();
 | 
			
		||||
    const { filter, loading: filterLoading } = useDiagramFilter();
 | 
			
		||||
    const { fitView, screenToFlowPosition, setNodes } = useReactFlow();
 | 
			
		||||
    const { tables, relationships, updateTablesState, filteredSchemas } =
 | 
			
		||||
        useChartDB();
 | 
			
		||||
    const { fitView } = useReactFlow();
 | 
			
		||||
    const [overlapGraph, setOverlapGraph] =
 | 
			
		||||
        useState<Graph<string>>(createGraph());
 | 
			
		||||
    const [editTableModeTable, setEditTableModeTable] = useState<{
 | 
			
		||||
        tableId: string;
 | 
			
		||||
        fieldId?: string;
 | 
			
		||||
    } | null>(null);
 | 
			
		||||
 | 
			
		||||
    const events = useEventEmitter<CanvasEvent>();
 | 
			
		||||
 | 
			
		||||
    const [showFilter, setShowFilter] = useState(false);
 | 
			
		||||
 | 
			
		||||
    const [tempFloatingEdge, setTempFloatingEdge] =
 | 
			
		||||
        useState<CanvasContext['tempFloatingEdge']>(null);
 | 
			
		||||
 | 
			
		||||
    const [hoveringTableId, setHoveringTableId] = useState<string | null>(null);
 | 
			
		||||
 | 
			
		||||
    const diagramIdActiveFilterRef = useRef<string>();
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (filterLoading) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (diagramIdActiveFilterRef.current === diagramId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        diagramIdActiveFilterRef.current = diagramId;
 | 
			
		||||
 | 
			
		||||
        setShowFilter(true);
 | 
			
		||||
    }, [filterLoading, diagramId]);
 | 
			
		||||
 | 
			
		||||
    const reorderTables = useCallback(
 | 
			
		||||
        (
 | 
			
		||||
            options: { updateHistory?: boolean } = {
 | 
			
		||||
@@ -78,19 +32,9 @@ export const CanvasProvider = ({ children }: CanvasProviderProps) => {
 | 
			
		||||
            const newTables = adjustTablePositions({
 | 
			
		||||
                relationships,
 | 
			
		||||
                tables: tables.filter((table) =>
 | 
			
		||||
                    filterTable({
 | 
			
		||||
                        table: {
 | 
			
		||||
                            id: table.id,
 | 
			
		||||
                            schema: table.schema,
 | 
			
		||||
                        },
 | 
			
		||||
                        filter,
 | 
			
		||||
                        options: {
 | 
			
		||||
                            defaultSchema: defaultSchemas[databaseType],
 | 
			
		||||
                        },
 | 
			
		||||
                    })
 | 
			
		||||
                    shouldShowTablesBySchemaFilter(table, filteredSchemas)
 | 
			
		||||
                ),
 | 
			
		||||
                areas,
 | 
			
		||||
                mode: 'all',
 | 
			
		||||
                mode: 'all', // Use 'all' mode for manual reordering
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const updatedOverlapGraph = findOverlappingTables({
 | 
			
		||||
@@ -125,77 +69,9 @@ export const CanvasProvider = ({ children }: CanvasProviderProps) => {
 | 
			
		||||
                });
 | 
			
		||||
            }, 500);
 | 
			
		||||
        },
 | 
			
		||||
        [
 | 
			
		||||
            filter,
 | 
			
		||||
            relationships,
 | 
			
		||||
            tables,
 | 
			
		||||
            updateTablesState,
 | 
			
		||||
            fitView,
 | 
			
		||||
            databaseType,
 | 
			
		||||
            areas,
 | 
			
		||||
        ]
 | 
			
		||||
        [filteredSchemas, relationships, tables, updateTablesState, fitView]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const startFloatingEdgeCreation: CanvasContext['startFloatingEdgeCreation'] =
 | 
			
		||||
        useCallback(({ sourceNodeId }) => {
 | 
			
		||||
            setShowFilter(false);
 | 
			
		||||
            setTempFloatingEdge({
 | 
			
		||||
                sourceNodeId,
 | 
			
		||||
            });
 | 
			
		||||
        }, []);
 | 
			
		||||
 | 
			
		||||
    const endFloatingEdgeCreation: CanvasContext['endFloatingEdgeCreation'] =
 | 
			
		||||
        useCallback(() => {
 | 
			
		||||
            setTempFloatingEdge(null);
 | 
			
		||||
        }, []);
 | 
			
		||||
 | 
			
		||||
    const hideCreateRelationshipNode: CanvasContext['hideCreateRelationshipNode'] =
 | 
			
		||||
        useCallback(() => {
 | 
			
		||||
            setNodes((nds) =>
 | 
			
		||||
                nds.filter((n) => n.id !== CREATE_RELATIONSHIP_NODE_ID)
 | 
			
		||||
            );
 | 
			
		||||
            endFloatingEdgeCreation();
 | 
			
		||||
        }, [setNodes, endFloatingEdgeCreation]);
 | 
			
		||||
 | 
			
		||||
    const showCreateRelationshipNode: CanvasContext['showCreateRelationshipNode'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            ({ sourceTableId, targetTableId, x, y }) => {
 | 
			
		||||
                setTempFloatingEdge((edge) =>
 | 
			
		||||
                    edge
 | 
			
		||||
                        ? {
 | 
			
		||||
                              ...edge,
 | 
			
		||||
                              targetNodeId: targetTableId,
 | 
			
		||||
                          }
 | 
			
		||||
                        : null
 | 
			
		||||
                );
 | 
			
		||||
                const cursorPos = screenToFlowPosition({
 | 
			
		||||
                    x,
 | 
			
		||||
                    y,
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                const newNode: CreateRelationshipNodeType = {
 | 
			
		||||
                    id: CREATE_RELATIONSHIP_NODE_ID,
 | 
			
		||||
                    type: 'create-relationship',
 | 
			
		||||
                    position: cursorPos,
 | 
			
		||||
                    data: {
 | 
			
		||||
                        sourceTableId,
 | 
			
		||||
                        targetTableId,
 | 
			
		||||
                    },
 | 
			
		||||
                    draggable: true,
 | 
			
		||||
                    selectable: false,
 | 
			
		||||
                    zIndex: 1000,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                setNodes((nds) => {
 | 
			
		||||
                    const nodesWithoutOldCreateRelationshipNode = nds.filter(
 | 
			
		||||
                        (n) => n.id !== CREATE_RELATIONSHIP_NODE_ID
 | 
			
		||||
                    );
 | 
			
		||||
                    return [...nodesWithoutOldCreateRelationshipNode, newNode];
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            [screenToFlowPosition, setNodes]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <canvasContext.Provider
 | 
			
		||||
            value={{
 | 
			
		||||
@@ -205,17 +81,6 @@ export const CanvasProvider = ({ children }: CanvasProviderProps) => {
 | 
			
		||||
                overlapGraph,
 | 
			
		||||
                setShowFilter,
 | 
			
		||||
                showFilter,
 | 
			
		||||
                editTableModeTable,
 | 
			
		||||
                setEditTableModeTable,
 | 
			
		||||
                tempFloatingEdge: tempFloatingEdge,
 | 
			
		||||
                setTempFloatingEdge: setTempFloatingEdge,
 | 
			
		||||
                startFloatingEdgeCreation: startFloatingEdgeCreation,
 | 
			
		||||
                endFloatingEdgeCreation: endFloatingEdgeCreation,
 | 
			
		||||
                hoveringTableId,
 | 
			
		||||
                setHoveringTableId,
 | 
			
		||||
                showCreateRelationshipNode,
 | 
			
		||||
                hideCreateRelationshipNode,
 | 
			
		||||
                events,
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            {children}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@ import type { DBDependency } from '@/lib/domain/db-dependency';
 | 
			
		||||
import { EventEmitter } from 'ahooks/lib/useEventEmitter';
 | 
			
		||||
import type { Area } from '@/lib/domain/area';
 | 
			
		||||
import type { DBCustomType } from '@/lib/domain/db-custom-type';
 | 
			
		||||
import type { Note } from '@/lib/domain/note';
 | 
			
		||||
 | 
			
		||||
export type ChartDBEventType =
 | 
			
		||||
    | 'add_tables'
 | 
			
		||||
@@ -75,13 +74,12 @@ export interface ChartDBContext {
 | 
			
		||||
    dependencies: DBDependency[];
 | 
			
		||||
    areas: Area[];
 | 
			
		||||
    customTypes: DBCustomType[];
 | 
			
		||||
    notes: Note[];
 | 
			
		||||
    currentDiagram: Diagram;
 | 
			
		||||
    events: EventEmitter<ChartDBEvent>;
 | 
			
		||||
    readonly?: boolean;
 | 
			
		||||
 | 
			
		||||
    highlightedCustomType?: DBCustomType;
 | 
			
		||||
    highlightCustomTypeId: (id?: string) => void;
 | 
			
		||||
    filteredSchemas?: string[];
 | 
			
		||||
    filterSchemas: (schemaIds: string[]) => void;
 | 
			
		||||
 | 
			
		||||
    // General operations
 | 
			
		||||
    updateDiagramId: (id: string) => Promise<void>;
 | 
			
		||||
@@ -94,10 +92,6 @@ export interface ChartDBContext {
 | 
			
		||||
    updateDiagramUpdatedAt: () => Promise<void>;
 | 
			
		||||
    clearDiagramData: () => Promise<void>;
 | 
			
		||||
    deleteDiagram: () => Promise<void>;
 | 
			
		||||
    updateDiagramData: (
 | 
			
		||||
        diagram: Diagram,
 | 
			
		||||
        options?: { forceUpdateStorage?: boolean }
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
 | 
			
		||||
    // Database type operations
 | 
			
		||||
    updateDatabaseType: (databaseType: DatabaseType) => Promise<void>;
 | 
			
		||||
@@ -257,31 +251,6 @@ export interface ChartDBContext {
 | 
			
		||||
        options?: { updateHistory: boolean }
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
 | 
			
		||||
    // Note operations
 | 
			
		||||
    createNote: (attributes?: Partial<Omit<Note, 'id'>>) => Promise<Note>;
 | 
			
		||||
    addNote: (
 | 
			
		||||
        note: Note,
 | 
			
		||||
        options?: { updateHistory: boolean }
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
    addNotes: (
 | 
			
		||||
        notes: Note[],
 | 
			
		||||
        options?: { updateHistory: boolean }
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
    getNote: (id: string) => Note | null;
 | 
			
		||||
    removeNote: (
 | 
			
		||||
        id: string,
 | 
			
		||||
        options?: { updateHistory: boolean }
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
    removeNotes: (
 | 
			
		||||
        ids: string[],
 | 
			
		||||
        options?: { updateHistory: boolean }
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
    updateNote: (
 | 
			
		||||
        id: string,
 | 
			
		||||
        note: Partial<Note>,
 | 
			
		||||
        options?: { updateHistory: boolean }
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
 | 
			
		||||
    // Custom type operations
 | 
			
		||||
    createCustomType: (
 | 
			
		||||
        attributes?: Partial<Omit<DBCustomType, 'id'>>
 | 
			
		||||
@@ -308,6 +277,11 @@ export interface ChartDBContext {
 | 
			
		||||
        customType: Partial<DBCustomType>,
 | 
			
		||||
        options?: { updateHistory: boolean }
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
 | 
			
		||||
    // Filters
 | 
			
		||||
    hiddenTableIds?: string[];
 | 
			
		||||
    addHiddenTableId: (tableId: string) => Promise<void>;
 | 
			
		||||
    removeHiddenTableId: (tableId: string) => Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const chartDBContext = createContext<ChartDBContext>({
 | 
			
		||||
@@ -319,9 +293,9 @@ export const chartDBContext = createContext<ChartDBContext>({
 | 
			
		||||
    dependencies: [],
 | 
			
		||||
    areas: [],
 | 
			
		||||
    customTypes: [],
 | 
			
		||||
    notes: [],
 | 
			
		||||
    schemas: [],
 | 
			
		||||
    highlightCustomTypeId: emptyFn,
 | 
			
		||||
    filteredSchemas: [],
 | 
			
		||||
    filterSchemas: emptyFn,
 | 
			
		||||
    currentDiagram: {
 | 
			
		||||
        id: '',
 | 
			
		||||
        name: '',
 | 
			
		||||
@@ -339,7 +313,6 @@ export const chartDBContext = createContext<ChartDBContext>({
 | 
			
		||||
    loadDiagramFromData: emptyFn,
 | 
			
		||||
    clearDiagramData: emptyFn,
 | 
			
		||||
    deleteDiagram: emptyFn,
 | 
			
		||||
    updateDiagramData: emptyFn,
 | 
			
		||||
 | 
			
		||||
    // Database type operations
 | 
			
		||||
    updateDatabaseType: emptyFn,
 | 
			
		||||
@@ -396,15 +369,6 @@ export const chartDBContext = createContext<ChartDBContext>({
 | 
			
		||||
    removeAreas: emptyFn,
 | 
			
		||||
    updateArea: emptyFn,
 | 
			
		||||
 | 
			
		||||
    // Note operations
 | 
			
		||||
    createNote: emptyFn,
 | 
			
		||||
    addNote: emptyFn,
 | 
			
		||||
    addNotes: emptyFn,
 | 
			
		||||
    getNote: emptyFn,
 | 
			
		||||
    removeNote: emptyFn,
 | 
			
		||||
    removeNotes: emptyFn,
 | 
			
		||||
    updateNote: emptyFn,
 | 
			
		||||
 | 
			
		||||
    // Custom type operations
 | 
			
		||||
    createCustomType: emptyFn,
 | 
			
		||||
    addCustomType: emptyFn,
 | 
			
		||||
@@ -413,4 +377,9 @@ export const chartDBContext = createContext<ChartDBContext>({
 | 
			
		||||
    removeCustomType: emptyFn,
 | 
			
		||||
    removeCustomTypes: emptyFn,
 | 
			
		||||
    updateCustomType: emptyFn,
 | 
			
		||||
 | 
			
		||||
    // Filters
 | 
			
		||||
    hiddenTableIds: [],
 | 
			
		||||
    addHiddenTableId: emptyFn,
 | 
			
		||||
    removeHiddenTableId: emptyFn,
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,12 @@
 | 
			
		||||
import React, { useCallback, useMemo, useState } from 'react';
 | 
			
		||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
 | 
			
		||||
import type { DBTable } from '@/lib/domain/db-table';
 | 
			
		||||
import { deepCopy, generateId } from '@/lib/utils';
 | 
			
		||||
import { defaultTableColor, defaultAreaColor, viewColor } from '@/lib/colors';
 | 
			
		||||
import { randomColor } from '@/lib/colors';
 | 
			
		||||
import type { ChartDBContext, ChartDBEvent } from './chartdb-context';
 | 
			
		||||
import { chartDBContext } from './chartdb-context';
 | 
			
		||||
import { DatabaseType } from '@/lib/domain/database-type';
 | 
			
		||||
import type { DBField } from '@/lib/domain/db-field';
 | 
			
		||||
import {
 | 
			
		||||
    getTableIndexesWithPrimaryKey,
 | 
			
		||||
    type DBIndex,
 | 
			
		||||
} from '@/lib/domain/db-index';
 | 
			
		||||
import type { DBIndex } from '@/lib/domain/db-index';
 | 
			
		||||
import type { DBRelationship } from '@/lib/domain/db-relationship';
 | 
			
		||||
import { useStorage } from '@/hooks/use-storage';
 | 
			
		||||
import { useRedoUndoStack } from '@/hooks/use-redo-undo-stack';
 | 
			
		||||
@@ -20,11 +17,11 @@ import {
 | 
			
		||||
    databasesWithSchemas,
 | 
			
		||||
    schemaNameToSchemaId,
 | 
			
		||||
} from '@/lib/domain/db-schema';
 | 
			
		||||
import { useLocalConfig } from '@/hooks/use-local-config';
 | 
			
		||||
import { defaultSchemas } from '@/lib/data/default-schemas';
 | 
			
		||||
import { useEventEmitter } from 'ahooks';
 | 
			
		||||
import type { DBDependency } from '@/lib/domain/db-dependency';
 | 
			
		||||
import type { Area } from '@/lib/domain/area';
 | 
			
		||||
import type { Note } from '@/lib/domain/note';
 | 
			
		||||
import { storageInitialValue } from '../storage-context/storage-context';
 | 
			
		||||
import { useDiff } from '../diff-context/use-diff';
 | 
			
		||||
import type { DiffCalculatedEvent } from '../diff-context/diff-context';
 | 
			
		||||
@@ -32,6 +29,7 @@ import {
 | 
			
		||||
    DBCustomTypeKind,
 | 
			
		||||
    type DBCustomType,
 | 
			
		||||
} from '@/lib/domain/db-custom-type';
 | 
			
		||||
import { useConfig } from '@/hooks/use-config';
 | 
			
		||||
 | 
			
		||||
export interface ChartDBProviderProps {
 | 
			
		||||
    diagram?: Diagram;
 | 
			
		||||
@@ -42,11 +40,16 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
    React.PropsWithChildren<ChartDBProviderProps>
 | 
			
		||||
> = ({ children, diagram, readonly: readonlyProp }) => {
 | 
			
		||||
    const { hasDiff } = useDiff();
 | 
			
		||||
    const storageDB = useStorage();
 | 
			
		||||
    let db = useStorage();
 | 
			
		||||
    const events = useEventEmitter<ChartDBEvent>();
 | 
			
		||||
    const { setSchemasFilter, schemasFilter } = useLocalConfig();
 | 
			
		||||
    const { addUndoAction, resetRedoStack, resetUndoStack } =
 | 
			
		||||
        useRedoUndoStack();
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
        getHiddenTablesForDiagram,
 | 
			
		||||
        hideTableForDiagram,
 | 
			
		||||
        unhideTableForDiagram,
 | 
			
		||||
    } = useConfig();
 | 
			
		||||
    const [diagramId, setDiagramId] = useState('');
 | 
			
		||||
    const [diagramName, setDiagramName] = useState('');
 | 
			
		||||
    const [diagramCreatedAt, setDiagramCreatedAt] = useState<Date>(new Date());
 | 
			
		||||
@@ -68,18 +71,14 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
    const [customTypes, setCustomTypes] = useState<DBCustomType[]>(
 | 
			
		||||
        diagram?.customTypes ?? []
 | 
			
		||||
    );
 | 
			
		||||
    const [notes, setNotes] = useState<Note[]>(diagram?.notes ?? []);
 | 
			
		||||
 | 
			
		||||
    const [hiddenTableIds, setHiddenTableIds] = useState<string[]>([]);
 | 
			
		||||
    const { events: diffEvents } = useDiff();
 | 
			
		||||
 | 
			
		||||
    const [highlightedCustomTypeId, setHighlightedCustomTypeId] =
 | 
			
		||||
        useState<string>();
 | 
			
		||||
 | 
			
		||||
    const diffCalculatedHandler = useCallback((event: DiffCalculatedEvent) => {
 | 
			
		||||
        const { tablesToAdd, fieldsToAdd, relationshipsToAdd } = event.data;
 | 
			
		||||
        const { tablesAdded, fieldsAdded, relationshipsAdded } = event.data;
 | 
			
		||||
        setTables((tables) =>
 | 
			
		||||
            [...tables, ...(tablesToAdd ?? [])].map((table) => {
 | 
			
		||||
                const fields = fieldsToAdd.get(table.id);
 | 
			
		||||
            [...tables, ...(tablesAdded ?? [])].map((table) => {
 | 
			
		||||
                const fields = fieldsAdded.get(table.id);
 | 
			
		||||
                return fields
 | 
			
		||||
                    ? { ...table, fields: [...table.fields, ...fields] }
 | 
			
		||||
                    : table;
 | 
			
		||||
@@ -87,22 +86,31 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
        );
 | 
			
		||||
        setRelationships((relationships) => [
 | 
			
		||||
            ...relationships,
 | 
			
		||||
            ...(relationshipsToAdd ?? []),
 | 
			
		||||
            ...(relationshipsAdded ?? []),
 | 
			
		||||
        ]);
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    diffEvents.useSubscription(diffCalculatedHandler);
 | 
			
		||||
 | 
			
		||||
    const defaultSchemaName = useMemo(
 | 
			
		||||
        () => defaultSchemas[databaseType],
 | 
			
		||||
        [databaseType]
 | 
			
		||||
    );
 | 
			
		||||
    // Sync hiddenTableIds with config
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (diagramId) {
 | 
			
		||||
            const hiddenTables = getHiddenTablesForDiagram(diagramId);
 | 
			
		||||
            setHiddenTableIds(hiddenTables);
 | 
			
		||||
        }
 | 
			
		||||
    }, [diagramId, getHiddenTablesForDiagram]);
 | 
			
		||||
 | 
			
		||||
    const defaultSchemaName = defaultSchemas[databaseType];
 | 
			
		||||
 | 
			
		||||
    const readonly = useMemo(
 | 
			
		||||
        () => readonlyProp ?? hasDiff ?? false,
 | 
			
		||||
        [readonlyProp, hasDiff]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (readonly) {
 | 
			
		||||
        db = storageInitialValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const schemas = useMemo(
 | 
			
		||||
        () =>
 | 
			
		||||
            databasesWithSchemas.includes(databaseType)
 | 
			
		||||
@@ -113,11 +121,9 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                              .filter((schema) => !!schema) as string[]
 | 
			
		||||
                      ),
 | 
			
		||||
                  ]
 | 
			
		||||
                      .sort((a, b) => {
 | 
			
		||||
                          if (a === defaultSchemaName) return -1;
 | 
			
		||||
                          if (b === defaultSchemaName) return 1;
 | 
			
		||||
                          return a.localeCompare(b);
 | 
			
		||||
                      })
 | 
			
		||||
                      .sort((a, b) =>
 | 
			
		||||
                          a === defaultSchemaName ? -1 : a.localeCompare(b)
 | 
			
		||||
                      )
 | 
			
		||||
                      .map(
 | 
			
		||||
                          (schema): DBSchema => ({
 | 
			
		||||
                              id: schemaNameToSchemaId(schema),
 | 
			
		||||
@@ -131,11 +137,34 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
        [tables, defaultSchemaName, databaseType]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const db = useMemo(
 | 
			
		||||
        () => (readonly ? storageInitialValue : storageDB),
 | 
			
		||||
        [storageDB, readonly]
 | 
			
		||||
    const filterSchemas: ChartDBContext['filterSchemas'] = useCallback(
 | 
			
		||||
        (schemaIds) => {
 | 
			
		||||
            setSchemasFilter((prev) => ({
 | 
			
		||||
                ...prev,
 | 
			
		||||
                [diagramId]: schemaIds,
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        [diagramId, setSchemasFilter]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const filteredSchemas: ChartDBContext['filteredSchemas'] = useMemo(() => {
 | 
			
		||||
        if (schemas.length === 0) {
 | 
			
		||||
            return undefined;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const schemasFilterFromCache =
 | 
			
		||||
            (schemasFilter[diagramId] ?? []).length === 0
 | 
			
		||||
                ? undefined // in case of empty filter, skip cache
 | 
			
		||||
                : schemasFilter[diagramId];
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            schemasFilterFromCache ?? [
 | 
			
		||||
                schemas.find((s) => s.name === defaultSchemaName)?.id ??
 | 
			
		||||
                    schemas[0]?.id,
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
    }, [schemasFilter, diagramId, schemas, defaultSchemaName]);
 | 
			
		||||
 | 
			
		||||
    const currentDiagram: Diagram = useMemo(
 | 
			
		||||
        () => ({
 | 
			
		||||
            id: diagramId,
 | 
			
		||||
@@ -149,7 +178,6 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
            dependencies,
 | 
			
		||||
            areas,
 | 
			
		||||
            customTypes,
 | 
			
		||||
            notes,
 | 
			
		||||
        }),
 | 
			
		||||
        [
 | 
			
		||||
            diagramId,
 | 
			
		||||
@@ -161,7 +189,6 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
            dependencies,
 | 
			
		||||
            areas,
 | 
			
		||||
            customTypes,
 | 
			
		||||
            notes,
 | 
			
		||||
            diagramCreatedAt,
 | 
			
		||||
            diagramUpdatedAt,
 | 
			
		||||
        ]
 | 
			
		||||
@@ -175,7 +202,6 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
            setDependencies([]);
 | 
			
		||||
            setAreas([]);
 | 
			
		||||
            setCustomTypes([]);
 | 
			
		||||
            setNotes([]);
 | 
			
		||||
            setDiagramUpdatedAt(updatedAt);
 | 
			
		||||
 | 
			
		||||
            resetRedoStack();
 | 
			
		||||
@@ -188,7 +214,6 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                db.deleteDiagramDependencies(diagramId),
 | 
			
		||||
                db.deleteDiagramAreas(diagramId),
 | 
			
		||||
                db.deleteDiagramCustomTypes(diagramId),
 | 
			
		||||
                db.deleteDiagramNotes(diagramId),
 | 
			
		||||
            ]);
 | 
			
		||||
        }, [db, diagramId, resetRedoStack, resetUndoStack]);
 | 
			
		||||
 | 
			
		||||
@@ -203,7 +228,6 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
            setDependencies([]);
 | 
			
		||||
            setAreas([]);
 | 
			
		||||
            setCustomTypes([]);
 | 
			
		||||
            setNotes([]);
 | 
			
		||||
            resetRedoStack();
 | 
			
		||||
            resetUndoStack();
 | 
			
		||||
 | 
			
		||||
@@ -214,7 +238,6 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                db.deleteDiagramDependencies(diagramId),
 | 
			
		||||
                db.deleteDiagramAreas(diagramId),
 | 
			
		||||
                db.deleteDiagramCustomTypes(diagramId),
 | 
			
		||||
                db.deleteDiagramNotes(diagramId),
 | 
			
		||||
            ]);
 | 
			
		||||
        }, [db, diagramId, resetRedoStack, resetUndoStack]);
 | 
			
		||||
 | 
			
		||||
@@ -353,18 +376,12 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                indexes: [],
 | 
			
		||||
                color: attributes?.isView ? viewColor : defaultTableColor,
 | 
			
		||||
                color: randomColor(),
 | 
			
		||||
                createdAt: Date.now(),
 | 
			
		||||
                isView: false,
 | 
			
		||||
                order: tables.length,
 | 
			
		||||
                ...attributes,
 | 
			
		||||
                schema: attributes?.schema ?? defaultSchemas[databaseType],
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            table.indexes = getTableIndexesWithPrimaryKey({
 | 
			
		||||
                table,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            await addTable(table);
 | 
			
		||||
 | 
			
		||||
            return table;
 | 
			
		||||
@@ -656,30 +673,17 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
            options = { updateHistory: true }
 | 
			
		||||
        ) => {
 | 
			
		||||
            const prevField = getField(tableId, fieldId);
 | 
			
		||||
 | 
			
		||||
            const updateTableFn = (table: DBTable) => {
 | 
			
		||||
                const updatedTable: DBTable = {
 | 
			
		||||
                    ...table,
 | 
			
		||||
                    fields: table.fields.map((f) =>
 | 
			
		||||
                        f.id === fieldId ? { ...f, ...field } : f
 | 
			
		||||
                    ),
 | 
			
		||||
                } satisfies DBTable;
 | 
			
		||||
 | 
			
		||||
                updatedTable.indexes = getTableIndexesWithPrimaryKey({
 | 
			
		||||
                    table: updatedTable,
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return updatedTable;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            setTables((tables) =>
 | 
			
		||||
                tables.map((table) => {
 | 
			
		||||
                    if (table.id === tableId) {
 | 
			
		||||
                        return updateTableFn(table);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return table;
 | 
			
		||||
                })
 | 
			
		||||
                tables.map((table) =>
 | 
			
		||||
                    table.id === tableId
 | 
			
		||||
                        ? {
 | 
			
		||||
                              ...table,
 | 
			
		||||
                              fields: table.fields.map((f) =>
 | 
			
		||||
                                  f.id === fieldId ? { ...f, ...field } : f
 | 
			
		||||
                              ),
 | 
			
		||||
                          }
 | 
			
		||||
                        : table
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const table = await db.getTable({ diagramId, id: tableId });
 | 
			
		||||
@@ -694,7 +698,10 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                db.updateTable({
 | 
			
		||||
                    id: tableId,
 | 
			
		||||
                    attributes: {
 | 
			
		||||
                        ...updateTableFn(table),
 | 
			
		||||
                        ...table,
 | 
			
		||||
                        fields: table.fields.map((f) =>
 | 
			
		||||
                            f.id === fieldId ? { ...f, ...field } : f
 | 
			
		||||
                        ),
 | 
			
		||||
                    },
 | 
			
		||||
                }),
 | 
			
		||||
            ]);
 | 
			
		||||
@@ -721,29 +728,19 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
            fieldId: string,
 | 
			
		||||
            options = { updateHistory: true }
 | 
			
		||||
        ) => {
 | 
			
		||||
            const updateTableFn = (table: DBTable) => {
 | 
			
		||||
                const updatedTable: DBTable = {
 | 
			
		||||
                    ...table,
 | 
			
		||||
                    fields: table.fields.filter((f) => f.id !== fieldId),
 | 
			
		||||
                } satisfies DBTable;
 | 
			
		||||
 | 
			
		||||
                updatedTable.indexes = getTableIndexesWithPrimaryKey({
 | 
			
		||||
                    table: updatedTable,
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return updatedTable;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const fields = getTable(tableId)?.fields ?? [];
 | 
			
		||||
            const prevField = getField(tableId, fieldId);
 | 
			
		||||
            setTables((tables) =>
 | 
			
		||||
                tables.map((table) => {
 | 
			
		||||
                    if (table.id === tableId) {
 | 
			
		||||
                        return updateTableFn(table);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return table;
 | 
			
		||||
                })
 | 
			
		||||
                tables.map((table) =>
 | 
			
		||||
                    table.id === tableId
 | 
			
		||||
                        ? {
 | 
			
		||||
                              ...table,
 | 
			
		||||
                              fields: table.fields.filter(
 | 
			
		||||
                                  (f) => f.id !== fieldId
 | 
			
		||||
                              ),
 | 
			
		||||
                          }
 | 
			
		||||
                        : table
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            events.emit({
 | 
			
		||||
@@ -767,7 +764,8 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                db.updateTable({
 | 
			
		||||
                    id: tableId,
 | 
			
		||||
                    attributes: {
 | 
			
		||||
                        ...updateTableFn(table),
 | 
			
		||||
                        ...table,
 | 
			
		||||
                        fields: table.fields.filter((f) => f.id !== fieldId),
 | 
			
		||||
                    },
 | 
			
		||||
                }),
 | 
			
		||||
            ]);
 | 
			
		||||
@@ -1123,15 +1121,12 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
 | 
			
		||||
                const sourceFieldName = sourceField?.name ?? '';
 | 
			
		||||
 | 
			
		||||
                const targetTable = getTable(targetTableId);
 | 
			
		||||
                const targetTableSchema = targetTable?.schema;
 | 
			
		||||
 | 
			
		||||
                const relationship: DBRelationship = {
 | 
			
		||||
                    id: generateId(),
 | 
			
		||||
                    name: `${sourceTableName}_${sourceFieldName}_fk`,
 | 
			
		||||
                    sourceSchema: sourceTable?.schema,
 | 
			
		||||
                    sourceTableId,
 | 
			
		||||
                    targetSchema: targetTableSchema,
 | 
			
		||||
                    targetSchema: sourceTable?.schema,
 | 
			
		||||
                    targetTableId,
 | 
			
		||||
                    sourceFieldId,
 | 
			
		||||
                    targetFieldId,
 | 
			
		||||
@@ -1453,7 +1448,7 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                y: 0,
 | 
			
		||||
                width: 300,
 | 
			
		||||
                height: 200,
 | 
			
		||||
                color: defaultAreaColor,
 | 
			
		||||
                color: randomColor(),
 | 
			
		||||
                ...attributes,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
@@ -1536,162 +1531,22 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
        [db, diagramId, setAreas, getArea, addUndoAction, resetRedoStack]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Note operations
 | 
			
		||||
    const addNotes: ChartDBContext['addNotes'] = useCallback(
 | 
			
		||||
        async (notes: Note[], options = { updateHistory: true }) => {
 | 
			
		||||
            setNotes((currentNotes) => [...currentNotes, ...notes]);
 | 
			
		||||
 | 
			
		||||
            const updatedAt = new Date();
 | 
			
		||||
            setDiagramUpdatedAt(updatedAt);
 | 
			
		||||
 | 
			
		||||
            await Promise.all([
 | 
			
		||||
                ...notes.map((note) => db.addNote({ diagramId, note })),
 | 
			
		||||
                db.updateDiagram({ id: diagramId, attributes: { updatedAt } }),
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            if (options.updateHistory) {
 | 
			
		||||
                addUndoAction({
 | 
			
		||||
                    action: 'addNotes',
 | 
			
		||||
                    redoData: { notes },
 | 
			
		||||
                    undoData: { noteIds: notes.map((n) => n.id) },
 | 
			
		||||
                });
 | 
			
		||||
                resetRedoStack();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [db, diagramId, setNotes, addUndoAction, resetRedoStack]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const addNote: ChartDBContext['addNote'] = useCallback(
 | 
			
		||||
        async (note: Note, options = { updateHistory: true }) => {
 | 
			
		||||
            return addNotes([note], options);
 | 
			
		||||
        },
 | 
			
		||||
        [addNotes]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const createNote: ChartDBContext['createNote'] = useCallback(
 | 
			
		||||
        async (attributes) => {
 | 
			
		||||
            const note: Note = {
 | 
			
		||||
                id: generateId(),
 | 
			
		||||
                content: '',
 | 
			
		||||
                x: 0,
 | 
			
		||||
                y: 0,
 | 
			
		||||
                width: 200,
 | 
			
		||||
                height: 150,
 | 
			
		||||
                color: '#ffe374', // Default warm yellow
 | 
			
		||||
                ...attributes,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            await addNote(note);
 | 
			
		||||
 | 
			
		||||
            return note;
 | 
			
		||||
        },
 | 
			
		||||
        [addNote]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getNote: ChartDBContext['getNote'] = useCallback(
 | 
			
		||||
        (id: string) => notes.find((note) => note.id === id) ?? null,
 | 
			
		||||
        [notes]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const removeNotes: ChartDBContext['removeNotes'] = useCallback(
 | 
			
		||||
        async (ids: string[], options = { updateHistory: true }) => {
 | 
			
		||||
            const prevNotes = [
 | 
			
		||||
                ...notes.filter((note) => ids.includes(note.id)),
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            setNotes((notes) => notes.filter((note) => !ids.includes(note.id)));
 | 
			
		||||
 | 
			
		||||
            const updatedAt = new Date();
 | 
			
		||||
            setDiagramUpdatedAt(updatedAt);
 | 
			
		||||
 | 
			
		||||
            await Promise.all([
 | 
			
		||||
                ...ids.map((id) => db.deleteNote({ diagramId, id })),
 | 
			
		||||
                db.updateDiagram({ id: diagramId, attributes: { updatedAt } }),
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            if (prevNotes.length > 0 && options.updateHistory) {
 | 
			
		||||
                addUndoAction({
 | 
			
		||||
                    action: 'removeNotes',
 | 
			
		||||
                    redoData: { noteIds: ids },
 | 
			
		||||
                    undoData: { notes: prevNotes },
 | 
			
		||||
                });
 | 
			
		||||
                resetRedoStack();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [db, diagramId, setNotes, notes, addUndoAction, resetRedoStack]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const removeNote: ChartDBContext['removeNote'] = useCallback(
 | 
			
		||||
        async (id: string, options = { updateHistory: true }) => {
 | 
			
		||||
            return removeNotes([id], options);
 | 
			
		||||
        },
 | 
			
		||||
        [removeNotes]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const updateNote: ChartDBContext['updateNote'] = useCallback(
 | 
			
		||||
        async (
 | 
			
		||||
            id: string,
 | 
			
		||||
            note: Partial<Note>,
 | 
			
		||||
            options = { updateHistory: true }
 | 
			
		||||
        ) => {
 | 
			
		||||
            const prevNote = getNote(id);
 | 
			
		||||
 | 
			
		||||
            setNotes((notes) =>
 | 
			
		||||
                notes.map((n) => (n.id === id ? { ...n, ...note } : n))
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const updatedAt = new Date();
 | 
			
		||||
            setDiagramUpdatedAt(updatedAt);
 | 
			
		||||
 | 
			
		||||
            await Promise.all([
 | 
			
		||||
                db.updateDiagram({ id: diagramId, attributes: { updatedAt } }),
 | 
			
		||||
                db.updateNote({ id, attributes: note }),
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            if (!!prevNote && options.updateHistory) {
 | 
			
		||||
                addUndoAction({
 | 
			
		||||
                    action: 'updateNote',
 | 
			
		||||
                    redoData: { noteId: id, note },
 | 
			
		||||
                    undoData: { noteId: id, note: prevNote },
 | 
			
		||||
                });
 | 
			
		||||
                resetRedoStack();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [db, diagramId, setNotes, getNote, addUndoAction, resetRedoStack]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const highlightCustomTypeId = useCallback(
 | 
			
		||||
        (id?: string) => setHighlightedCustomTypeId(id),
 | 
			
		||||
        [setHighlightedCustomTypeId]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const highlightedCustomType = useMemo(() => {
 | 
			
		||||
        return highlightedCustomTypeId
 | 
			
		||||
            ? customTypes.find((type) => type.id === highlightedCustomTypeId)
 | 
			
		||||
            : undefined;
 | 
			
		||||
    }, [highlightedCustomTypeId, customTypes]);
 | 
			
		||||
 | 
			
		||||
    const loadDiagramFromData: ChartDBContext['loadDiagramFromData'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            (diagram) => {
 | 
			
		||||
            async (diagram) => {
 | 
			
		||||
                setDiagramId(diagram.id);
 | 
			
		||||
                setDiagramName(diagram.name);
 | 
			
		||||
                setDatabaseType(diagram.databaseType);
 | 
			
		||||
                setDatabaseEdition(diagram.databaseEdition);
 | 
			
		||||
                setTables(diagram.tables ?? []);
 | 
			
		||||
                setRelationships(diagram.relationships ?? []);
 | 
			
		||||
                setDependencies(diagram.dependencies ?? []);
 | 
			
		||||
                setAreas(diagram.areas ?? []);
 | 
			
		||||
                setCustomTypes(diagram.customTypes ?? []);
 | 
			
		||||
                setTables(diagram?.tables ?? []);
 | 
			
		||||
                setRelationships(diagram?.relationships ?? []);
 | 
			
		||||
                setDependencies(diagram?.dependencies ?? []);
 | 
			
		||||
                setAreas(diagram?.areas ?? []);
 | 
			
		||||
                setCustomTypes(diagram?.customTypes ?? []);
 | 
			
		||||
                setDiagramCreatedAt(diagram.createdAt);
 | 
			
		||||
                setDiagramUpdatedAt(diagram.updatedAt);
 | 
			
		||||
                setHighlightedCustomTypeId(undefined);
 | 
			
		||||
                setNotes(diagram.notes ?? []);
 | 
			
		||||
 | 
			
		||||
                events.emit({ action: 'load_diagram', data: { diagram } });
 | 
			
		||||
 | 
			
		||||
                resetRedoStack();
 | 
			
		||||
                resetUndoStack();
 | 
			
		||||
            },
 | 
			
		||||
            [
 | 
			
		||||
                setDiagramId,
 | 
			
		||||
@@ -1705,33 +1560,18 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                setCustomTypes,
 | 
			
		||||
                setDiagramCreatedAt,
 | 
			
		||||
                setDiagramUpdatedAt,
 | 
			
		||||
                setHighlightedCustomTypeId,
 | 
			
		||||
                events,
 | 
			
		||||
                setNotes,
 | 
			
		||||
                resetRedoStack,
 | 
			
		||||
                resetUndoStack,
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const updateDiagramData: ChartDBContext['updateDiagramData'] = useCallback(
 | 
			
		||||
        async (diagram, options) => {
 | 
			
		||||
            const st = options?.forceUpdateStorage ? storageDB : db;
 | 
			
		||||
            await st.deleteDiagram(diagram.id);
 | 
			
		||||
            await st.addDiagram({ diagram });
 | 
			
		||||
            loadDiagramFromData(diagram);
 | 
			
		||||
        },
 | 
			
		||||
        [db, storageDB, loadDiagramFromData]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const loadDiagram: ChartDBContext['loadDiagram'] = useCallback(
 | 
			
		||||
        async (diagramId: string) => {
 | 
			
		||||
            const diagram = await storageDB.getDiagram(diagramId, {
 | 
			
		||||
            const diagram = await db.getDiagram(diagramId, {
 | 
			
		||||
                includeRelationships: true,
 | 
			
		||||
                includeTables: true,
 | 
			
		||||
                includeDependencies: true,
 | 
			
		||||
                includeAreas: true,
 | 
			
		||||
                includeCustomTypes: true,
 | 
			
		||||
                includeNotes: true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (diagram) {
 | 
			
		||||
@@ -1740,7 +1580,7 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
 | 
			
		||||
            return diagram;
 | 
			
		||||
        },
 | 
			
		||||
        [storageDB, loadDiagramFromData]
 | 
			
		||||
        [db, loadDiagramFromData]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Custom type operations
 | 
			
		||||
@@ -1887,6 +1727,29 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const addHiddenTableId: ChartDBContext['addHiddenTableId'] = useCallback(
 | 
			
		||||
        async (tableId: string) => {
 | 
			
		||||
            if (!hiddenTableIds.includes(tableId)) {
 | 
			
		||||
                setHiddenTableIds((prev) => [...prev, tableId]);
 | 
			
		||||
                await hideTableForDiagram(diagramId, tableId);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [hiddenTableIds, diagramId, hideTableForDiagram]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const removeHiddenTableId: ChartDBContext['removeHiddenTableId'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            async (tableId: string) => {
 | 
			
		||||
                if (hiddenTableIds.includes(tableId)) {
 | 
			
		||||
                    setHiddenTableIds((prev) =>
 | 
			
		||||
                        prev.filter((id) => id !== tableId)
 | 
			
		||||
                    );
 | 
			
		||||
                    await unhideTableForDiagram(diagramId, tableId);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            [hiddenTableIds, diagramId, unhideTableForDiagram]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <chartDBContext.Provider
 | 
			
		||||
            value={{
 | 
			
		||||
@@ -1897,12 +1760,12 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                relationships,
 | 
			
		||||
                dependencies,
 | 
			
		||||
                areas,
 | 
			
		||||
                notes,
 | 
			
		||||
                currentDiagram,
 | 
			
		||||
                schemas,
 | 
			
		||||
                filteredSchemas,
 | 
			
		||||
                events,
 | 
			
		||||
                readonly,
 | 
			
		||||
                updateDiagramData,
 | 
			
		||||
                filterSchemas,
 | 
			
		||||
                updateDiagramId,
 | 
			
		||||
                updateDiagramName,
 | 
			
		||||
                loadDiagram,
 | 
			
		||||
@@ -1959,15 +1822,9 @@ export const ChartDBProvider: React.FC<
 | 
			
		||||
                removeCustomType,
 | 
			
		||||
                removeCustomTypes,
 | 
			
		||||
                updateCustomType,
 | 
			
		||||
                highlightCustomTypeId,
 | 
			
		||||
                highlightedCustomType,
 | 
			
		||||
                createNote,
 | 
			
		||||
                addNote,
 | 
			
		||||
                addNotes,
 | 
			
		||||
                getNote,
 | 
			
		||||
                removeNote,
 | 
			
		||||
                removeNotes,
 | 
			
		||||
                updateNote,
 | 
			
		||||
                hiddenTableIds,
 | 
			
		||||
                addHiddenTableId,
 | 
			
		||||
                removeHiddenTableId,
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            {children}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,23 @@ export interface ConfigContext {
 | 
			
		||||
        config?: Partial<ChartDBConfig>;
 | 
			
		||||
        updateFn?: (config: ChartDBConfig) => ChartDBConfig;
 | 
			
		||||
    }) => Promise<void>;
 | 
			
		||||
    getHiddenTablesForDiagram: (diagramId: string) => string[];
 | 
			
		||||
    setHiddenTablesForDiagram: (
 | 
			
		||||
        diagramId: string,
 | 
			
		||||
        hiddenTableIds: string[]
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
    hideTableForDiagram: (diagramId: string, tableId: string) => Promise<void>;
 | 
			
		||||
    unhideTableForDiagram: (
 | 
			
		||||
        diagramId: string,
 | 
			
		||||
        tableId: string
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ConfigContext = createContext<ConfigContext>({
 | 
			
		||||
    config: undefined,
 | 
			
		||||
    updateConfig: emptyFn,
 | 
			
		||||
    getHiddenTablesForDiagram: () => [],
 | 
			
		||||
    setHiddenTablesForDiagram: emptyFn,
 | 
			
		||||
    hideTableForDiagram: emptyFn,
 | 
			
		||||
    unhideTableForDiagram: emptyFn,
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import React, { useEffect } from 'react';
 | 
			
		||||
import { ConfigContext } from './config-context';
 | 
			
		||||
 | 
			
		||||
import { useStorage } from '@/hooks/use-storage';
 | 
			
		||||
@@ -8,7 +8,7 @@ export const ConfigProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    children,
 | 
			
		||||
}) => {
 | 
			
		||||
    const { getConfig, updateConfig: updateDataConfig } = useStorage();
 | 
			
		||||
    const [config, setConfig] = useState<ChartDBConfig | undefined>();
 | 
			
		||||
    const [config, setConfig] = React.useState<ChartDBConfig | undefined>();
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        const loadConfig = async () => {
 | 
			
		||||
@@ -44,11 +44,84 @@ export const ConfigProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
        return promise;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const getHiddenTablesForDiagram = (diagramId: string): string[] => {
 | 
			
		||||
        return config?.hiddenTablesByDiagram?.[diagramId] ?? [];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const setHiddenTablesForDiagram = async (
 | 
			
		||||
        diagramId: string,
 | 
			
		||||
        hiddenTableIds: string[]
 | 
			
		||||
    ): Promise<void> => {
 | 
			
		||||
        return updateConfig({
 | 
			
		||||
            updateFn: (currentConfig) => ({
 | 
			
		||||
                ...currentConfig,
 | 
			
		||||
                hiddenTablesByDiagram: {
 | 
			
		||||
                    ...currentConfig.hiddenTablesByDiagram,
 | 
			
		||||
                    [diagramId]: hiddenTableIds,
 | 
			
		||||
                },
 | 
			
		||||
            }),
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const hideTableForDiagram = async (
 | 
			
		||||
        diagramId: string,
 | 
			
		||||
        tableId: string
 | 
			
		||||
    ): Promise<void> => {
 | 
			
		||||
        return updateConfig({
 | 
			
		||||
            updateFn: (currentConfig) => {
 | 
			
		||||
                const currentHiddenTables =
 | 
			
		||||
                    currentConfig.hiddenTablesByDiagram?.[diagramId] ?? [];
 | 
			
		||||
                if (currentHiddenTables.includes(tableId)) {
 | 
			
		||||
                    return currentConfig; // Already hidden, no change needed
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    ...currentConfig,
 | 
			
		||||
                    hiddenTablesByDiagram: {
 | 
			
		||||
                        ...currentConfig.hiddenTablesByDiagram,
 | 
			
		||||
                        [diagramId]: [...currentHiddenTables, tableId],
 | 
			
		||||
                    },
 | 
			
		||||
                };
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const unhideTableForDiagram = async (
 | 
			
		||||
        diagramId: string,
 | 
			
		||||
        tableId: string
 | 
			
		||||
    ): Promise<void> => {
 | 
			
		||||
        return updateConfig({
 | 
			
		||||
            updateFn: (currentConfig) => {
 | 
			
		||||
                const currentHiddenTables =
 | 
			
		||||
                    currentConfig.hiddenTablesByDiagram?.[diagramId] ?? [];
 | 
			
		||||
                const filteredTables = currentHiddenTables.filter(
 | 
			
		||||
                    (id) => id !== tableId
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                if (filteredTables.length === currentHiddenTables.length) {
 | 
			
		||||
                    return currentConfig; // Not hidden, no change needed
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    ...currentConfig,
 | 
			
		||||
                    hiddenTablesByDiagram: {
 | 
			
		||||
                        ...currentConfig.hiddenTablesByDiagram,
 | 
			
		||||
                        [diagramId]: filteredTables,
 | 
			
		||||
                    },
 | 
			
		||||
                };
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <ConfigContext.Provider
 | 
			
		||||
            value={{
 | 
			
		||||
                config,
 | 
			
		||||
                updateConfig,
 | 
			
		||||
                getHiddenTablesForDiagram,
 | 
			
		||||
                setHiddenTablesForDiagram,
 | 
			
		||||
                hideTableForDiagram,
 | 
			
		||||
                unhideTableForDiagram,
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            {children}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
import type { DBSchema } from '@/lib/domain';
 | 
			
		||||
import type {
 | 
			
		||||
    DiagramFilter,
 | 
			
		||||
    FilterTableInfo,
 | 
			
		||||
} from '@/lib/domain/diagram-filter/diagram-filter';
 | 
			
		||||
import { emptyFn } from '@/lib/utils';
 | 
			
		||||
import { createContext } from 'react';
 | 
			
		||||
 | 
			
		||||
export interface DiagramFilterContext {
 | 
			
		||||
    filter?: DiagramFilter;
 | 
			
		||||
    loading: boolean;
 | 
			
		||||
 | 
			
		||||
    hasActiveFilter: boolean;
 | 
			
		||||
    schemasDisplayed: DBSchema[];
 | 
			
		||||
 | 
			
		||||
    clearSchemaIdsFilter: () => void;
 | 
			
		||||
    clearTableIdsFilter: () => void;
 | 
			
		||||
 | 
			
		||||
    setTableIdsFilterEmpty: () => void;
 | 
			
		||||
 | 
			
		||||
    // reset
 | 
			
		||||
    resetFilter: () => void;
 | 
			
		||||
 | 
			
		||||
    toggleSchemaFilter: (schemaId: string) => void;
 | 
			
		||||
    toggleTableFilter: (tableId: string) => void;
 | 
			
		||||
    addSchemaToFilter: (schemaId: string) => void;
 | 
			
		||||
    addTablesToFilter: (attrs: {
 | 
			
		||||
        tableIds?: string[];
 | 
			
		||||
        filterCallback?: (table: FilterTableInfo) => boolean;
 | 
			
		||||
    }) => void;
 | 
			
		||||
    removeTablesFromFilter: (attrs: {
 | 
			
		||||
        tableIds?: string[];
 | 
			
		||||
        filterCallback?: (table: FilterTableInfo) => boolean;
 | 
			
		||||
    }) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const diagramFilterContext = createContext<DiagramFilterContext>({
 | 
			
		||||
    hasActiveFilter: false,
 | 
			
		||||
    clearSchemaIdsFilter: emptyFn,
 | 
			
		||||
    clearTableIdsFilter: emptyFn,
 | 
			
		||||
    setTableIdsFilterEmpty: emptyFn,
 | 
			
		||||
    resetFilter: emptyFn,
 | 
			
		||||
    toggleSchemaFilter: emptyFn,
 | 
			
		||||
    toggleTableFilter: emptyFn,
 | 
			
		||||
    addSchemaToFilter: emptyFn,
 | 
			
		||||
    schemasDisplayed: [],
 | 
			
		||||
    addTablesToFilter: emptyFn,
 | 
			
		||||
    removeTablesFromFilter: emptyFn,
 | 
			
		||||
    loading: false,
 | 
			
		||||
});
 | 
			
		||||
@@ -1,559 +0,0 @@
 | 
			
		||||
import React, {
 | 
			
		||||
    useCallback,
 | 
			
		||||
    useEffect,
 | 
			
		||||
    useMemo,
 | 
			
		||||
    useRef,
 | 
			
		||||
    useState,
 | 
			
		||||
} from 'react';
 | 
			
		||||
import type { DiagramFilterContext } from './diagram-filter-context';
 | 
			
		||||
import { diagramFilterContext } from './diagram-filter-context';
 | 
			
		||||
import type {
 | 
			
		||||
    DiagramFilter,
 | 
			
		||||
    FilterTableInfo,
 | 
			
		||||
} from '@/lib/domain/diagram-filter/diagram-filter';
 | 
			
		||||
import {
 | 
			
		||||
    reduceFilter,
 | 
			
		||||
    spreadFilterTables,
 | 
			
		||||
} from '@/lib/domain/diagram-filter/diagram-filter';
 | 
			
		||||
import { useStorage } from '@/hooks/use-storage';
 | 
			
		||||
import { useChartDB } from '@/hooks/use-chartdb';
 | 
			
		||||
import { filterTable } from '@/lib/domain/diagram-filter/filter';
 | 
			
		||||
import { databasesWithSchemas, schemaNameToSchemaId } from '@/lib/domain';
 | 
			
		||||
import { defaultSchemas } from '@/lib/data/default-schemas';
 | 
			
		||||
import type { ChartDBEvent } from '../chartdb-context/chartdb-context';
 | 
			
		||||
 | 
			
		||||
export const DiagramFilterProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    children,
 | 
			
		||||
}) => {
 | 
			
		||||
    const { diagramId, tables, schemas, databaseType, events } = useChartDB();
 | 
			
		||||
    const { getDiagramFilter, updateDiagramFilter } = useStorage();
 | 
			
		||||
    const [filter, setFilter] = useState<DiagramFilter>({});
 | 
			
		||||
    const [loading, setLoading] = useState<boolean>(true);
 | 
			
		||||
 | 
			
		||||
    const allSchemasIds = useMemo(() => {
 | 
			
		||||
        return schemas.map((schema) => schema.id);
 | 
			
		||||
    }, [schemas]);
 | 
			
		||||
 | 
			
		||||
    const allTables: FilterTableInfo[] = useMemo(() => {
 | 
			
		||||
        return tables.map(
 | 
			
		||||
            (table) =>
 | 
			
		||||
                ({
 | 
			
		||||
                    id: table.id,
 | 
			
		||||
                    schemaId: table.schema
 | 
			
		||||
                        ? schemaNameToSchemaId(table.schema)
 | 
			
		||||
                        : defaultSchemas[databaseType],
 | 
			
		||||
                    schema: table.schema ?? defaultSchemas[databaseType],
 | 
			
		||||
                    areaId: table.parentAreaId ?? undefined,
 | 
			
		||||
                }) satisfies FilterTableInfo
 | 
			
		||||
        );
 | 
			
		||||
    }, [tables, databaseType]);
 | 
			
		||||
 | 
			
		||||
    const diagramIdOfLoadedFilter = useRef<string | null>(null);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (diagramId && diagramId === diagramIdOfLoadedFilter.current) {
 | 
			
		||||
            updateDiagramFilter(diagramId, filter);
 | 
			
		||||
        }
 | 
			
		||||
    }, [diagramId, filter, updateDiagramFilter]);
 | 
			
		||||
 | 
			
		||||
    // Reset filter when diagram changes
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (diagramIdOfLoadedFilter.current === diagramId) {
 | 
			
		||||
            // If the diagramId hasn't changed, do not reset the filter
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setLoading(true);
 | 
			
		||||
 | 
			
		||||
        const loadFilterFromStorage = async (diagramId: string) => {
 | 
			
		||||
            if (diagramId) {
 | 
			
		||||
                const storedFilter = await getDiagramFilter(diagramId);
 | 
			
		||||
 | 
			
		||||
                let filterToSet = storedFilter;
 | 
			
		||||
 | 
			
		||||
                if (!filterToSet) {
 | 
			
		||||
                    // If no filter is stored, set default based on database type
 | 
			
		||||
                    filterToSet =
 | 
			
		||||
                        schemas.length > 1
 | 
			
		||||
                            ? { schemaIds: [schemas[0].id] }
 | 
			
		||||
                            : {};
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                setFilter(filterToSet);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setLoading(false);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        setFilter({});
 | 
			
		||||
 | 
			
		||||
        if (diagramId) {
 | 
			
		||||
            loadFilterFromStorage(diagramId);
 | 
			
		||||
            diagramIdOfLoadedFilter.current = diagramId;
 | 
			
		||||
        }
 | 
			
		||||
    }, [diagramId, getDiagramFilter, schemas]);
 | 
			
		||||
 | 
			
		||||
    const clearSchemaIds: DiagramFilterContext['clearSchemaIdsFilter'] =
 | 
			
		||||
        useCallback(() => {
 | 
			
		||||
            setFilter(
 | 
			
		||||
                (prev) =>
 | 
			
		||||
                    ({
 | 
			
		||||
                        ...prev,
 | 
			
		||||
                        schemaIds: undefined,
 | 
			
		||||
                    }) satisfies DiagramFilter
 | 
			
		||||
            );
 | 
			
		||||
        }, []);
 | 
			
		||||
 | 
			
		||||
    const clearTableIds: DiagramFilterContext['clearTableIdsFilter'] =
 | 
			
		||||
        useCallback(() => {
 | 
			
		||||
            setFilter(
 | 
			
		||||
                (prev) =>
 | 
			
		||||
                    ({
 | 
			
		||||
                        ...prev,
 | 
			
		||||
                        tableIds: undefined,
 | 
			
		||||
                    }) satisfies DiagramFilter
 | 
			
		||||
            );
 | 
			
		||||
        }, []);
 | 
			
		||||
 | 
			
		||||
    const setTableIdsEmpty: DiagramFilterContext['setTableIdsFilterEmpty'] =
 | 
			
		||||
        useCallback(() => {
 | 
			
		||||
            setFilter(
 | 
			
		||||
                (prev) =>
 | 
			
		||||
                    ({
 | 
			
		||||
                        ...prev,
 | 
			
		||||
                        tableIds: [],
 | 
			
		||||
                    }) satisfies DiagramFilter
 | 
			
		||||
            );
 | 
			
		||||
        }, []);
 | 
			
		||||
 | 
			
		||||
    // Reset filter
 | 
			
		||||
    const resetFilter: DiagramFilterContext['resetFilter'] = useCallback(() => {
 | 
			
		||||
        setFilter({});
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    const toggleSchemaFilter: DiagramFilterContext['toggleSchemaFilter'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            (schemaId: string) => {
 | 
			
		||||
                setFilter((prev) => {
 | 
			
		||||
                    const currentSchemaIds = prev.schemaIds;
 | 
			
		||||
 | 
			
		||||
                    // Check if schema is currently visible
 | 
			
		||||
                    const isSchemaVisible = !allTables.some(
 | 
			
		||||
                        (table) =>
 | 
			
		||||
                            table.schemaId === schemaId &&
 | 
			
		||||
                            filterTable({
 | 
			
		||||
                                table: {
 | 
			
		||||
                                    id: table.id,
 | 
			
		||||
                                    schema: table.schema,
 | 
			
		||||
                                },
 | 
			
		||||
                                filter: prev,
 | 
			
		||||
                                options: {
 | 
			
		||||
                                    defaultSchema: defaultSchemas[databaseType],
 | 
			
		||||
                                },
 | 
			
		||||
                            }) === false
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    let newSchemaIds: string[] | undefined;
 | 
			
		||||
                    let newTableIds: string[] | undefined = prev.tableIds;
 | 
			
		||||
 | 
			
		||||
                    if (isSchemaVisible) {
 | 
			
		||||
                        // Schema is visible, make it not visible
 | 
			
		||||
                        if (!currentSchemaIds) {
 | 
			
		||||
                            // All schemas are visible, create filter with all except this one
 | 
			
		||||
                            newSchemaIds = allSchemasIds.filter(
 | 
			
		||||
                                (id) => id !== schemaId
 | 
			
		||||
                            );
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Remove this schema from the filter
 | 
			
		||||
                            newSchemaIds = currentSchemaIds.filter(
 | 
			
		||||
                                (id) => id !== schemaId
 | 
			
		||||
                            );
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // Remove tables from this schema from tableIds if present
 | 
			
		||||
                        if (prev.tableIds) {
 | 
			
		||||
                            const schemaTableIds = allTables
 | 
			
		||||
                                .filter((table) => table.schemaId === schemaId)
 | 
			
		||||
                                .map((table) => table.id);
 | 
			
		||||
                            newTableIds = prev.tableIds.filter(
 | 
			
		||||
                                (id) => !schemaTableIds.includes(id)
 | 
			
		||||
                            );
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Schema is not visible, make it visible
 | 
			
		||||
                        newSchemaIds = [
 | 
			
		||||
                            ...new Set([...(currentSchemaIds || []), schemaId]),
 | 
			
		||||
                        ];
 | 
			
		||||
 | 
			
		||||
                        // Add tables from this schema to tableIds if tableIds is defined
 | 
			
		||||
                        if (prev.tableIds) {
 | 
			
		||||
                            const schemaTableIds = allTables
 | 
			
		||||
                                .filter((table) => table.schemaId === schemaId)
 | 
			
		||||
                                .map((table) => table.id);
 | 
			
		||||
                            newTableIds = [
 | 
			
		||||
                                ...new Set([
 | 
			
		||||
                                    ...prev.tableIds,
 | 
			
		||||
                                    ...schemaTableIds,
 | 
			
		||||
                                ]),
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Use reduceFilter to optimize and handle edge cases
 | 
			
		||||
                    return reduceFilter(
 | 
			
		||||
                        {
 | 
			
		||||
                            schemaIds: newSchemaIds,
 | 
			
		||||
                            tableIds: newTableIds,
 | 
			
		||||
                        },
 | 
			
		||||
                        allTables satisfies FilterTableInfo[],
 | 
			
		||||
                        {
 | 
			
		||||
                            databaseWithSchemas:
 | 
			
		||||
                                databasesWithSchemas.includes(databaseType),
 | 
			
		||||
                        }
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            [allSchemasIds, allTables, databaseType]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const toggleTableFilterForNoSchema = useCallback(
 | 
			
		||||
        (tableId: string) => {
 | 
			
		||||
            setFilter((prev) => {
 | 
			
		||||
                const currentTableIds = prev.tableIds;
 | 
			
		||||
 | 
			
		||||
                // Check if table is currently visible
 | 
			
		||||
                const isTableVisible = filterTable({
 | 
			
		||||
                    table: { id: tableId, schema: undefined },
 | 
			
		||||
                    filter: prev,
 | 
			
		||||
                    options: { defaultSchema: undefined },
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                let newTableIds: string[] | undefined;
 | 
			
		||||
 | 
			
		||||
                if (isTableVisible) {
 | 
			
		||||
                    // Table is visible, make it not visible
 | 
			
		||||
                    if (!currentTableIds) {
 | 
			
		||||
                        // All tables are visible, create filter with all except this one
 | 
			
		||||
                        newTableIds = allTables
 | 
			
		||||
                            .filter((t) => t.id !== tableId)
 | 
			
		||||
                            .map((t) => t.id);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Remove this table from the filter
 | 
			
		||||
                        newTableIds = currentTableIds.filter(
 | 
			
		||||
                            (id) => id !== tableId
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Table is not visible, make it visible
 | 
			
		||||
                    newTableIds = [
 | 
			
		||||
                        ...new Set([...(currentTableIds || []), tableId]),
 | 
			
		||||
                    ];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Use reduceFilter to optimize and handle edge cases
 | 
			
		||||
                return reduceFilter(
 | 
			
		||||
                    {
 | 
			
		||||
                        schemaIds: undefined,
 | 
			
		||||
                        tableIds: newTableIds,
 | 
			
		||||
                    },
 | 
			
		||||
                    allTables satisfies FilterTableInfo[],
 | 
			
		||||
                    {
 | 
			
		||||
                        databaseWithSchemas:
 | 
			
		||||
                            databasesWithSchemas.includes(databaseType),
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        [allTables, databaseType]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const toggleTableFilter: DiagramFilterContext['toggleTableFilter'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            (tableId: string) => {
 | 
			
		||||
                if (!databasesWithSchemas.includes(databaseType)) {
 | 
			
		||||
                    // No schemas, toggle table filter without schema context
 | 
			
		||||
                    toggleTableFilterForNoSchema(tableId);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                setFilter((prev) => {
 | 
			
		||||
                    // Find the table in the tables list
 | 
			
		||||
                    const tableInfo = allTables.find((t) => t.id === tableId);
 | 
			
		||||
 | 
			
		||||
                    if (!tableInfo) {
 | 
			
		||||
                        return prev;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Check if table is currently visible using filterTable
 | 
			
		||||
                    const isTableVisible = filterTable({
 | 
			
		||||
                        table: {
 | 
			
		||||
                            id: tableInfo.id,
 | 
			
		||||
                            schema: tableInfo.schema,
 | 
			
		||||
                        },
 | 
			
		||||
                        filter: prev,
 | 
			
		||||
                        options: {
 | 
			
		||||
                            defaultSchema: defaultSchemas[databaseType],
 | 
			
		||||
                        },
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    let newSchemaIds = prev.schemaIds;
 | 
			
		||||
                    let newTableIds = prev.tableIds;
 | 
			
		||||
 | 
			
		||||
                    if (isTableVisible) {
 | 
			
		||||
                        // Table is visible, make it not visible
 | 
			
		||||
 | 
			
		||||
                        // If the table is visible due to its schema being in schemaIds
 | 
			
		||||
                        if (
 | 
			
		||||
                            tableInfo?.schemaId &&
 | 
			
		||||
                            prev.schemaIds?.includes(tableInfo.schemaId)
 | 
			
		||||
                        ) {
 | 
			
		||||
                            // Remove the schema from schemaIds and add all other tables from that schema to tableIds
 | 
			
		||||
                            newSchemaIds = prev.schemaIds.filter(
 | 
			
		||||
                                (id) => id !== tableInfo.schemaId
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            // Get all other tables from this schema (except the one being toggled)
 | 
			
		||||
                            const otherTablesFromSchema = allTables
 | 
			
		||||
                                .filter(
 | 
			
		||||
                                    (t) =>
 | 
			
		||||
                                        t.schemaId === tableInfo.schemaId &&
 | 
			
		||||
                                        t.id !== tableId
 | 
			
		||||
                                )
 | 
			
		||||
                                .map((t) => t.id);
 | 
			
		||||
 | 
			
		||||
                            // Add these tables to tableIds
 | 
			
		||||
                            newTableIds = [
 | 
			
		||||
                                ...(prev.tableIds || []),
 | 
			
		||||
                                ...otherTablesFromSchema,
 | 
			
		||||
                            ];
 | 
			
		||||
                        } else if (prev.tableIds?.includes(tableId)) {
 | 
			
		||||
                            // Table is visible because it's in tableIds, remove it
 | 
			
		||||
                            newTableIds = prev.tableIds.filter(
 | 
			
		||||
                                (id) => id !== tableId
 | 
			
		||||
                            );
 | 
			
		||||
                        } else if (!prev.tableIds && !prev.schemaIds) {
 | 
			
		||||
                            // No filters = all visible, create filter with all tables except this one
 | 
			
		||||
                            newTableIds = allTables
 | 
			
		||||
                                .filter((t) => t.id !== tableId)
 | 
			
		||||
                                .map((t) => t.id);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Table is not visible, make it visible by adding to tableIds
 | 
			
		||||
                        newTableIds = [...(prev.tableIds || []), tableId];
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Use reduceFilter to optimize and handle edge cases
 | 
			
		||||
                    return reduceFilter(
 | 
			
		||||
                        {
 | 
			
		||||
                            schemaIds: newSchemaIds,
 | 
			
		||||
                            tableIds: newTableIds,
 | 
			
		||||
                        },
 | 
			
		||||
                        allTables satisfies FilterTableInfo[],
 | 
			
		||||
                        {
 | 
			
		||||
                            databaseWithSchemas:
 | 
			
		||||
                                databasesWithSchemas.includes(databaseType),
 | 
			
		||||
                        }
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            [allTables, databaseType, toggleTableFilterForNoSchema]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const addSchemaToFilter: DiagramFilterContext['addSchemaToFilter'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            (schemaId: string) => {
 | 
			
		||||
                setFilter((prev) => {
 | 
			
		||||
                    const currentSchemaIds = prev.schemaIds;
 | 
			
		||||
                    if (!currentSchemaIds) {
 | 
			
		||||
                        // No schemas are filtered
 | 
			
		||||
                        return prev;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // If schema is already filtered, do nothing
 | 
			
		||||
                    if (currentSchemaIds.includes(schemaId)) {
 | 
			
		||||
                        return prev;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Add schema to the filter
 | 
			
		||||
                    const newSchemaIds = [...currentSchemaIds, schemaId];
 | 
			
		||||
 | 
			
		||||
                    if (newSchemaIds.length === allSchemasIds.length) {
 | 
			
		||||
                        // All schemas are now filtered, set to undefined
 | 
			
		||||
                        return {
 | 
			
		||||
                            ...prev,
 | 
			
		||||
                            schemaIds: undefined,
 | 
			
		||||
                        } satisfies DiagramFilter;
 | 
			
		||||
                    }
 | 
			
		||||
                    return {
 | 
			
		||||
                        ...prev,
 | 
			
		||||
                        schemaIds: newSchemaIds,
 | 
			
		||||
                    } satisfies DiagramFilter;
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            [allSchemasIds.length]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const hasActiveFilter: boolean = useMemo(() => {
 | 
			
		||||
        return !!filter.schemaIds || !!filter.tableIds;
 | 
			
		||||
    }, [filter]);
 | 
			
		||||
 | 
			
		||||
    const schemasDisplayed: DiagramFilterContext['schemasDisplayed'] =
 | 
			
		||||
        useMemo(() => {
 | 
			
		||||
            if (!hasActiveFilter) {
 | 
			
		||||
                return schemas;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const displayedSchemaIds = new Set<string>();
 | 
			
		||||
            for (const table of allTables) {
 | 
			
		||||
                if (
 | 
			
		||||
                    filterTable({
 | 
			
		||||
                        table: {
 | 
			
		||||
                            id: table.id,
 | 
			
		||||
                            schema: table.schema,
 | 
			
		||||
                        },
 | 
			
		||||
                        filter,
 | 
			
		||||
                        options: {
 | 
			
		||||
                            defaultSchema: defaultSchemas[databaseType],
 | 
			
		||||
                        },
 | 
			
		||||
                    })
 | 
			
		||||
                ) {
 | 
			
		||||
                    if (table.schemaId) {
 | 
			
		||||
                        displayedSchemaIds.add(table.schemaId);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return schemas.filter((schema) =>
 | 
			
		||||
                displayedSchemaIds.has(schema.id)
 | 
			
		||||
            );
 | 
			
		||||
        }, [hasActiveFilter, schemas, allTables, filter, databaseType]);
 | 
			
		||||
 | 
			
		||||
    const addTablesToFilter: DiagramFilterContext['addTablesToFilter'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            ({ tableIds, filterCallback }) => {
 | 
			
		||||
                setFilter((prev) => {
 | 
			
		||||
                    let tableIdsToAdd: string[];
 | 
			
		||||
 | 
			
		||||
                    if (tableIds) {
 | 
			
		||||
                        // If tableIds are provided, use them directly
 | 
			
		||||
                        tableIdsToAdd = tableIds;
 | 
			
		||||
                    } else if (filterCallback) {
 | 
			
		||||
                        // If filterCallback is provided, filter tables based on it
 | 
			
		||||
                        tableIdsToAdd = allTables
 | 
			
		||||
                            .filter(filterCallback)
 | 
			
		||||
                            .map((table) => table.id);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // If neither is provided, do nothing
 | 
			
		||||
                        return prev;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    const filterByTableIds = spreadFilterTables(
 | 
			
		||||
                        prev,
 | 
			
		||||
                        allTables satisfies FilterTableInfo[]
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    const currentTableIds = filterByTableIds.tableIds || [];
 | 
			
		||||
                    const newTableIds = [
 | 
			
		||||
                        ...new Set([...currentTableIds, ...tableIdsToAdd]),
 | 
			
		||||
                    ];
 | 
			
		||||
 | 
			
		||||
                    return reduceFilter(
 | 
			
		||||
                        {
 | 
			
		||||
                            ...filterByTableIds,
 | 
			
		||||
                            tableIds: newTableIds,
 | 
			
		||||
                        },
 | 
			
		||||
                        allTables satisfies FilterTableInfo[],
 | 
			
		||||
                        {
 | 
			
		||||
                            databaseWithSchemas:
 | 
			
		||||
                                databasesWithSchemas.includes(databaseType),
 | 
			
		||||
                        }
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            [allTables, databaseType]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const removeTablesFromFilter: DiagramFilterContext['removeTablesFromFilter'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            ({ tableIds, filterCallback }) => {
 | 
			
		||||
                setFilter((prev) => {
 | 
			
		||||
                    let tableIdsToRemovoe: string[];
 | 
			
		||||
 | 
			
		||||
                    if (tableIds) {
 | 
			
		||||
                        // If tableIds are provided, use them directly
 | 
			
		||||
                        tableIdsToRemovoe = tableIds;
 | 
			
		||||
                    } else if (filterCallback) {
 | 
			
		||||
                        // If filterCallback is provided, filter tables based on it
 | 
			
		||||
                        tableIdsToRemovoe = allTables
 | 
			
		||||
                            .filter(filterCallback)
 | 
			
		||||
                            .map((table) => table.id);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // If neither is provided, do nothing
 | 
			
		||||
                        return prev;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    const filterByTableIds = spreadFilterTables(
 | 
			
		||||
                        prev,
 | 
			
		||||
                        allTables satisfies FilterTableInfo[]
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    const currentTableIds = filterByTableIds.tableIds || [];
 | 
			
		||||
                    const newTableIds = currentTableIds.filter(
 | 
			
		||||
                        (id) => !tableIdsToRemovoe.includes(id)
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    return reduceFilter(
 | 
			
		||||
                        {
 | 
			
		||||
                            ...filterByTableIds,
 | 
			
		||||
                            tableIds: newTableIds,
 | 
			
		||||
                        },
 | 
			
		||||
                        allTables satisfies FilterTableInfo[],
 | 
			
		||||
                        {
 | 
			
		||||
                            databaseWithSchemas:
 | 
			
		||||
                                databasesWithSchemas.includes(databaseType),
 | 
			
		||||
                        }
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            [allTables, databaseType]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const eventConsumer = useCallback(
 | 
			
		||||
        (event: ChartDBEvent) => {
 | 
			
		||||
            if (!hasActiveFilter) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (event.action === 'add_tables') {
 | 
			
		||||
                addTablesToFilter({
 | 
			
		||||
                    tableIds: event.data.tables.map((table) => table.id),
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [hasActiveFilter, addTablesToFilter]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    events.useSubscription(eventConsumer);
 | 
			
		||||
 | 
			
		||||
    const value: DiagramFilterContext = {
 | 
			
		||||
        loading,
 | 
			
		||||
        filter,
 | 
			
		||||
        clearSchemaIdsFilter: clearSchemaIds,
 | 
			
		||||
        setTableIdsFilterEmpty: setTableIdsEmpty,
 | 
			
		||||
        clearTableIdsFilter: clearTableIds,
 | 
			
		||||
        resetFilter,
 | 
			
		||||
        toggleSchemaFilter,
 | 
			
		||||
        toggleTableFilter,
 | 
			
		||||
        addSchemaToFilter,
 | 
			
		||||
        hasActiveFilter,
 | 
			
		||||
        schemasDisplayed,
 | 
			
		||||
        addTablesToFilter,
 | 
			
		||||
        removeTablesFromFilter,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <diagramFilterContext.Provider value={value}>
 | 
			
		||||
            {children}
 | 
			
		||||
        </diagramFilterContext.Provider>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@@ -1,4 +0,0 @@
 | 
			
		||||
import { useContext } from 'react';
 | 
			
		||||
import { diagramFilterContext } from './diagram-filter-context';
 | 
			
		||||
 | 
			
		||||
export const useDiagramFilter = () => useContext(diagramFilterContext);
 | 
			
		||||
@@ -7,6 +7,7 @@ import type { ExportImageDialogProps } from '@/dialogs/export-image-dialog/expor
 | 
			
		||||
import type { ExportDiagramDialogProps } from '@/dialogs/export-diagram-dialog/export-diagram-dialog';
 | 
			
		||||
import type { ImportDiagramDialogProps } from '@/dialogs/import-diagram-dialog/import-diagram-dialog';
 | 
			
		||||
import type { CreateRelationshipDialogProps } from '@/dialogs/create-relationship-dialog/create-relationship-dialog';
 | 
			
		||||
import type { ImportDBMLDialogProps } from '@/dialogs/import-dbml-dialog/import-dbml-dialog';
 | 
			
		||||
import type { OpenDiagramDialogProps } from '@/dialogs/open-diagram-dialog/open-diagram-dialog';
 | 
			
		||||
import type { CreateDiagramDialogProps } from '@/dialogs/create-diagram-dialog/create-diagram-dialog';
 | 
			
		||||
 | 
			
		||||
@@ -66,6 +67,12 @@ export interface DialogContext {
 | 
			
		||||
        params: Omit<ImportDiagramDialogProps, 'dialog'>
 | 
			
		||||
    ) => void;
 | 
			
		||||
    closeImportDiagramDialog: () => void;
 | 
			
		||||
 | 
			
		||||
    // Import DBML dialog
 | 
			
		||||
    openImportDBMLDialog: (
 | 
			
		||||
        params?: Omit<ImportDBMLDialogProps, 'dialog'>
 | 
			
		||||
    ) => void;
 | 
			
		||||
    closeImportDBMLDialog: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const dialogContext = createContext<DialogContext>({
 | 
			
		||||
@@ -89,4 +96,6 @@ export const dialogContext = createContext<DialogContext>({
 | 
			
		||||
    closeExportDiagramDialog: emptyFn,
 | 
			
		||||
    openImportDiagramDialog: emptyFn,
 | 
			
		||||
    closeImportDiagramDialog: emptyFn,
 | 
			
		||||
    openImportDBMLDialog: emptyFn,
 | 
			
		||||
    closeImportDBMLDialog: emptyFn,
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,8 @@ import type { ExportImageDialogProps } from '@/dialogs/export-image-dialog/expor
 | 
			
		||||
import { ExportImageDialog } from '@/dialogs/export-image-dialog/export-image-dialog';
 | 
			
		||||
import { ExportDiagramDialog } from '@/dialogs/export-diagram-dialog/export-diagram-dialog';
 | 
			
		||||
import { ImportDiagramDialog } from '@/dialogs/import-diagram-dialog/import-diagram-dialog';
 | 
			
		||||
import type { ImportDBMLDialogProps } from '@/dialogs/import-dbml-dialog/import-dbml-dialog';
 | 
			
		||||
import { ImportDBMLDialog } from '@/dialogs/import-dbml-dialog/import-dbml-dialog';
 | 
			
		||||
 | 
			
		||||
export const DialogProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    children,
 | 
			
		||||
@@ -130,6 +132,11 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    const [openImportDiagramDialog, setOpenImportDiagramDialog] =
 | 
			
		||||
        useState(false);
 | 
			
		||||
 | 
			
		||||
    // Import DBML dialog
 | 
			
		||||
    const [openImportDBMLDialog, setOpenImportDBMLDialog] = useState(false);
 | 
			
		||||
    const [importDBMLDialogParams, setImportDBMLDialogParams] =
 | 
			
		||||
        useState<Omit<ImportDBMLDialogProps, 'dialog'>>();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <dialogContext.Provider
 | 
			
		||||
            value={{
 | 
			
		||||
@@ -158,6 +165,11 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                openImportDiagramDialog: () => setOpenImportDiagramDialog(true),
 | 
			
		||||
                closeImportDiagramDialog: () =>
 | 
			
		||||
                    setOpenImportDiagramDialog(false),
 | 
			
		||||
                openImportDBMLDialog: (params) => {
 | 
			
		||||
                    setImportDBMLDialogParams(params);
 | 
			
		||||
                    setOpenImportDBMLDialog(true);
 | 
			
		||||
                },
 | 
			
		||||
                closeImportDBMLDialog: () => setOpenImportDBMLDialog(false),
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            {children}
 | 
			
		||||
@@ -192,6 +204,10 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            />
 | 
			
		||||
            <ExportDiagramDialog dialog={{ open: openExportDiagramDialog }} />
 | 
			
		||||
            <ImportDiagramDialog dialog={{ open: openImportDiagramDialog }} />
 | 
			
		||||
            <ImportDBMLDialog
 | 
			
		||||
                dialog={{ open: openImportDBMLDialog }}
 | 
			
		||||
                {...importDBMLDialogParams}
 | 
			
		||||
            />
 | 
			
		||||
        </dialogContext.Provider>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,9 @@ export type DiffEventBase<T extends DiffEventType, D> = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type DiffCalculatedData = {
 | 
			
		||||
    tablesToAdd: DBTable[];
 | 
			
		||||
    fieldsToAdd: Map<string, DBField[]>;
 | 
			
		||||
    relationshipsToAdd: DBRelationship[];
 | 
			
		||||
    tablesAdded: DBTable[];
 | 
			
		||||
    fieldsAdded: Map<string, DBField[]>;
 | 
			
		||||
    relationshipsAdded: DBRelationship[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type DiffCalculatedEvent = DiffEventBase<
 | 
			
		||||
@@ -32,33 +32,21 @@ export interface DiffContext {
 | 
			
		||||
    originalDiagram: Diagram | null;
 | 
			
		||||
    diffMap: DiffMap;
 | 
			
		||||
    hasDiff: boolean;
 | 
			
		||||
    isSummaryOnly: boolean;
 | 
			
		||||
 | 
			
		||||
    calculateDiff: ({
 | 
			
		||||
        diagram,
 | 
			
		||||
        newDiagram,
 | 
			
		||||
        options,
 | 
			
		||||
    }: {
 | 
			
		||||
        diagram: Diagram;
 | 
			
		||||
        newDiagram: Diagram;
 | 
			
		||||
        options?: {
 | 
			
		||||
            summaryOnly?: boolean;
 | 
			
		||||
        };
 | 
			
		||||
    }) => { foundDiff: boolean };
 | 
			
		||||
    resetDiff: () => void;
 | 
			
		||||
    }) => void;
 | 
			
		||||
 | 
			
		||||
    // table diff
 | 
			
		||||
    checkIfTableHasChange: ({ tableId }: { tableId: string }) => boolean;
 | 
			
		||||
    checkIfNewTable: ({ tableId }: { tableId: string }) => boolean;
 | 
			
		||||
    checkIfTableRemoved: ({ tableId }: { tableId: string }) => boolean;
 | 
			
		||||
    getTableNewName: ({ tableId }: { tableId: string }) => {
 | 
			
		||||
        old: string;
 | 
			
		||||
        new: string;
 | 
			
		||||
    } | null;
 | 
			
		||||
    getTableNewColor: ({ tableId }: { tableId: string }) => {
 | 
			
		||||
        old: string;
 | 
			
		||||
        new: string;
 | 
			
		||||
    } | null;
 | 
			
		||||
    getTableNewName: ({ tableId }: { tableId: string }) => string | null;
 | 
			
		||||
    getTableNewColor: ({ tableId }: { tableId: string }) => string | null;
 | 
			
		||||
 | 
			
		||||
    // field diff
 | 
			
		||||
    checkIfFieldHasChange: ({
 | 
			
		||||
@@ -70,46 +58,8 @@ export interface DiffContext {
 | 
			
		||||
    }) => boolean;
 | 
			
		||||
    checkIfFieldRemoved: ({ fieldId }: { fieldId: string }) => boolean;
 | 
			
		||||
    checkIfNewField: ({ fieldId }: { fieldId: string }) => boolean;
 | 
			
		||||
    getFieldNewName: ({
 | 
			
		||||
        fieldId,
 | 
			
		||||
    }: {
 | 
			
		||||
        fieldId: string;
 | 
			
		||||
    }) => { old: string; new: string } | null;
 | 
			
		||||
    getFieldNewType: ({
 | 
			
		||||
        fieldId,
 | 
			
		||||
    }: {
 | 
			
		||||
        fieldId: string;
 | 
			
		||||
    }) => { old: DataType; new: DataType } | null;
 | 
			
		||||
    getFieldNewPrimaryKey: ({
 | 
			
		||||
        fieldId,
 | 
			
		||||
    }: {
 | 
			
		||||
        fieldId: string;
 | 
			
		||||
    }) => { old: boolean; new: boolean } | null;
 | 
			
		||||
    getFieldNewNullable: ({
 | 
			
		||||
        fieldId,
 | 
			
		||||
    }: {
 | 
			
		||||
        fieldId: string;
 | 
			
		||||
    }) => { old: boolean; new: boolean } | null;
 | 
			
		||||
    getFieldNewCharacterMaximumLength: ({
 | 
			
		||||
        fieldId,
 | 
			
		||||
    }: {
 | 
			
		||||
        fieldId: string;
 | 
			
		||||
    }) => { old: string; new: string } | null;
 | 
			
		||||
    getFieldNewScale: ({
 | 
			
		||||
        fieldId,
 | 
			
		||||
    }: {
 | 
			
		||||
        fieldId: string;
 | 
			
		||||
    }) => { old: number; new: number } | null;
 | 
			
		||||
    getFieldNewPrecision: ({
 | 
			
		||||
        fieldId,
 | 
			
		||||
    }: {
 | 
			
		||||
        fieldId: string;
 | 
			
		||||
    }) => { old: number; new: number } | null;
 | 
			
		||||
    getFieldNewIsArray: ({
 | 
			
		||||
        fieldId,
 | 
			
		||||
    }: {
 | 
			
		||||
        fieldId: string;
 | 
			
		||||
    }) => { old: boolean; new: boolean } | null;
 | 
			
		||||
    getFieldNewName: ({ fieldId }: { fieldId: string }) => string | null;
 | 
			
		||||
    getFieldNewType: ({ fieldId }: { fieldId: string }) => DataType | null;
 | 
			
		||||
 | 
			
		||||
    // relationship diff
 | 
			
		||||
    checkIfNewRelationship: ({
 | 
			
		||||
 
 | 
			
		||||
@@ -32,11 +32,10 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    const [fieldsChanged, setFieldsChanged] = React.useState<
 | 
			
		||||
        Map<string, boolean>
 | 
			
		||||
    >(new Map<string, boolean>());
 | 
			
		||||
    const [isSummaryOnly, setIsSummaryOnly] = React.useState<boolean>(false);
 | 
			
		||||
 | 
			
		||||
    const events = useEventEmitter<DiffEvent>();
 | 
			
		||||
 | 
			
		||||
    const generateFieldsToAddMap = useCallback(
 | 
			
		||||
    const generateNewFieldsMap = useCallback(
 | 
			
		||||
        ({
 | 
			
		||||
            diffMap,
 | 
			
		||||
            newDiagram,
 | 
			
		||||
@@ -66,7 +65,7 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
        []
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const findRelationshipsToAdd = useCallback(
 | 
			
		||||
    const findNewRelationships = useCallback(
 | 
			
		||||
        ({
 | 
			
		||||
            diffMap,
 | 
			
		||||
            newDiagram,
 | 
			
		||||
@@ -101,7 +100,7 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            diffMap: DiffMap;
 | 
			
		||||
        }): DiffCalculatedData => {
 | 
			
		||||
            return {
 | 
			
		||||
                tablesToAdd:
 | 
			
		||||
                tablesAdded:
 | 
			
		||||
                    newDiagram?.tables?.filter((table) => {
 | 
			
		||||
                        const tableKey = getDiffMapKey({
 | 
			
		||||
                            diffObject: 'table',
 | 
			
		||||
@@ -114,21 +113,21 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                        );
 | 
			
		||||
                    }) ?? [],
 | 
			
		||||
 | 
			
		||||
                fieldsToAdd: generateFieldsToAddMap({
 | 
			
		||||
                fieldsAdded: generateNewFieldsMap({
 | 
			
		||||
                    diffMap: diffMap,
 | 
			
		||||
                    newDiagram: newDiagram,
 | 
			
		||||
                }),
 | 
			
		||||
                relationshipsToAdd: findRelationshipsToAdd({
 | 
			
		||||
                relationshipsAdded: findNewRelationships({
 | 
			
		||||
                    diffMap: diffMap,
 | 
			
		||||
                    newDiagram: newDiagram,
 | 
			
		||||
                }),
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        [findRelationshipsToAdd, generateFieldsToAddMap]
 | 
			
		||||
        [findNewRelationships, generateNewFieldsMap]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const calculateDiff: DiffContext['calculateDiff'] = useCallback(
 | 
			
		||||
        ({ diagram, newDiagram: newDiagramArg, options }) => {
 | 
			
		||||
        ({ diagram, newDiagram: newDiagramArg }) => {
 | 
			
		||||
            const {
 | 
			
		||||
                diffMap: newDiffs,
 | 
			
		||||
                changedTables: newChangedTables,
 | 
			
		||||
@@ -140,7 +139,6 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            setFieldsChanged(newChangedFields);
 | 
			
		||||
            setNewDiagram(newDiagramArg);
 | 
			
		||||
            setOriginalDiagram(diagram);
 | 
			
		||||
            setIsSummaryOnly(options?.summaryOnly ?? false);
 | 
			
		||||
 | 
			
		||||
            events.emit({
 | 
			
		||||
                action: 'diff_calculated',
 | 
			
		||||
@@ -149,8 +147,6 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                    newDiagram: newDiagramArg,
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return { foundDiff: !!newDiffs.size };
 | 
			
		||||
        },
 | 
			
		||||
        [setDiffMap, events, generateDiffCalculatedData]
 | 
			
		||||
    );
 | 
			
		||||
@@ -167,10 +163,7 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                const diff = diffMap.get(tableNameKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        new: diff.newValue as string,
 | 
			
		||||
                        old: diff.oldValue as string,
 | 
			
		||||
                    };
 | 
			
		||||
                    return diff.newValue as string;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -191,10 +184,7 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                const diff = diffMap.get(tableColorKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        new: diff.newValue as string,
 | 
			
		||||
                        old: diff.oldValue as string,
 | 
			
		||||
                    };
 | 
			
		||||
                    return diff.newValue as string;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
@@ -285,10 +275,7 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                const diff = diffMap.get(fieldKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        old: diff.oldValue as string,
 | 
			
		||||
                        new: diff.newValue as string,
 | 
			
		||||
                    };
 | 
			
		||||
                    return diff.newValue as string;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -309,160 +296,7 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                const diff = diffMap.get(fieldKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        old: diff.oldValue as DataType,
 | 
			
		||||
                        new: diff.newValue as DataType,
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        },
 | 
			
		||||
        [diffMap]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getFieldNewPrimaryKey = useCallback<
 | 
			
		||||
        DiffContext['getFieldNewPrimaryKey']
 | 
			
		||||
    >(
 | 
			
		||||
        ({ fieldId }) => {
 | 
			
		||||
            const fieldKey = getDiffMapKey({
 | 
			
		||||
                diffObject: 'field',
 | 
			
		||||
                objectId: fieldId,
 | 
			
		||||
                attribute: 'primaryKey',
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (diffMap.has(fieldKey)) {
 | 
			
		||||
                const diff = diffMap.get(fieldKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        old: diff.oldValue as boolean,
 | 
			
		||||
                        new: diff.newValue as boolean,
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        },
 | 
			
		||||
        [diffMap]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getFieldNewNullable = useCallback<DiffContext['getFieldNewNullable']>(
 | 
			
		||||
        ({ fieldId }) => {
 | 
			
		||||
            const fieldKey = getDiffMapKey({
 | 
			
		||||
                diffObject: 'field',
 | 
			
		||||
                objectId: fieldId,
 | 
			
		||||
                attribute: 'nullable',
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (diffMap.has(fieldKey)) {
 | 
			
		||||
                const diff = diffMap.get(fieldKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        old: diff.oldValue as boolean,
 | 
			
		||||
                        new: diff.newValue as boolean,
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        },
 | 
			
		||||
        [diffMap]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getFieldNewCharacterMaximumLength = useCallback<
 | 
			
		||||
        DiffContext['getFieldNewCharacterMaximumLength']
 | 
			
		||||
    >(
 | 
			
		||||
        ({ fieldId }) => {
 | 
			
		||||
            const fieldKey = getDiffMapKey({
 | 
			
		||||
                diffObject: 'field',
 | 
			
		||||
                objectId: fieldId,
 | 
			
		||||
                attribute: 'characterMaximumLength',
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (diffMap.has(fieldKey)) {
 | 
			
		||||
                const diff = diffMap.get(fieldKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        old: diff.oldValue as string,
 | 
			
		||||
                        new: diff.newValue as string,
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        },
 | 
			
		||||
        [diffMap]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getFieldNewScale = useCallback<DiffContext['getFieldNewScale']>(
 | 
			
		||||
        ({ fieldId }) => {
 | 
			
		||||
            const fieldKey = getDiffMapKey({
 | 
			
		||||
                diffObject: 'field',
 | 
			
		||||
                objectId: fieldId,
 | 
			
		||||
                attribute: 'scale',
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (diffMap.has(fieldKey)) {
 | 
			
		||||
                const diff = diffMap.get(fieldKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        old: diff.oldValue as number,
 | 
			
		||||
                        new: diff.newValue as number,
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        },
 | 
			
		||||
        [diffMap]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getFieldNewPrecision = useCallback<
 | 
			
		||||
        DiffContext['getFieldNewPrecision']
 | 
			
		||||
    >(
 | 
			
		||||
        ({ fieldId }) => {
 | 
			
		||||
            const fieldKey = getDiffMapKey({
 | 
			
		||||
                diffObject: 'field',
 | 
			
		||||
                objectId: fieldId,
 | 
			
		||||
                attribute: 'precision',
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (diffMap.has(fieldKey)) {
 | 
			
		||||
                const diff = diffMap.get(fieldKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        old: diff.oldValue as number,
 | 
			
		||||
                        new: diff.newValue as number,
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        },
 | 
			
		||||
        [diffMap]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getFieldNewIsArray = useCallback<DiffContext['getFieldNewIsArray']>(
 | 
			
		||||
        ({ fieldId }) => {
 | 
			
		||||
            const fieldKey = getDiffMapKey({
 | 
			
		||||
                diffObject: 'field',
 | 
			
		||||
                objectId: fieldId,
 | 
			
		||||
                attribute: 'isArray',
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (diffMap.has(fieldKey)) {
 | 
			
		||||
                const diff = diffMap.get(fieldKey);
 | 
			
		||||
 | 
			
		||||
                if (diff?.type === 'changed') {
 | 
			
		||||
                    return {
 | 
			
		||||
                        old: diff.oldValue as boolean,
 | 
			
		||||
                        new: diff.newValue as boolean,
 | 
			
		||||
                    };
 | 
			
		||||
                    return diff.newValue as DataType;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -505,15 +339,6 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
        [diffMap]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const resetDiff = useCallback<DiffContext['resetDiff']>(() => {
 | 
			
		||||
        setDiffMap(new Map<string, ChartDBDiff>());
 | 
			
		||||
        setTablesChanged(new Map<string, boolean>());
 | 
			
		||||
        setFieldsChanged(new Map<string, boolean>());
 | 
			
		||||
        setNewDiagram(null);
 | 
			
		||||
        setOriginalDiagram(null);
 | 
			
		||||
        setIsSummaryOnly(false);
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <diffContext.Provider
 | 
			
		||||
            value={{
 | 
			
		||||
@@ -521,10 +346,8 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                originalDiagram,
 | 
			
		||||
                diffMap,
 | 
			
		||||
                hasDiff: diffMap.size > 0,
 | 
			
		||||
                isSummaryOnly,
 | 
			
		||||
 | 
			
		||||
                calculateDiff,
 | 
			
		||||
                resetDiff,
 | 
			
		||||
 | 
			
		||||
                // table diff
 | 
			
		||||
                getTableNewName,
 | 
			
		||||
@@ -539,12 +362,6 @@ export const DiffProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                checkIfNewField,
 | 
			
		||||
                getFieldNewName,
 | 
			
		||||
                getFieldNewType,
 | 
			
		||||
                getFieldNewPrimaryKey,
 | 
			
		||||
                getFieldNewNullable,
 | 
			
		||||
                getFieldNewCharacterMaximumLength,
 | 
			
		||||
                getFieldNewScale,
 | 
			
		||||
                getFieldNewPrecision,
 | 
			
		||||
                getFieldNewIsArray,
 | 
			
		||||
 | 
			
		||||
                // relationship diff
 | 
			
		||||
                checkIfNewRelationship,
 | 
			
		||||
 
 | 
			
		||||
@@ -39,9 +39,6 @@ export const HistoryProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
        addCustomTypes,
 | 
			
		||||
        removeCustomTypes,
 | 
			
		||||
        updateCustomType,
 | 
			
		||||
        addNotes,
 | 
			
		||||
        removeNotes,
 | 
			
		||||
        updateNote,
 | 
			
		||||
    } = useChartDB();
 | 
			
		||||
 | 
			
		||||
    const redoActionHandlers = useMemo(
 | 
			
		||||
@@ -138,15 +135,6 @@ export const HistoryProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                    updateHistory: false,
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            addNotes: ({ redoData: { notes } }) => {
 | 
			
		||||
                return addNotes(notes, { updateHistory: false });
 | 
			
		||||
            },
 | 
			
		||||
            removeNotes: ({ redoData: { noteIds } }) => {
 | 
			
		||||
                return removeNotes(noteIds, { updateHistory: false });
 | 
			
		||||
            },
 | 
			
		||||
            updateNote: ({ redoData: { noteId, note } }) => {
 | 
			
		||||
                return updateNote(noteId, note, { updateHistory: false });
 | 
			
		||||
            },
 | 
			
		||||
        }),
 | 
			
		||||
        [
 | 
			
		||||
            addTables,
 | 
			
		||||
@@ -172,9 +160,6 @@ export const HistoryProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            addCustomTypes,
 | 
			
		||||
            removeCustomTypes,
 | 
			
		||||
            updateCustomType,
 | 
			
		||||
            addNotes,
 | 
			
		||||
            removeNotes,
 | 
			
		||||
            updateNote,
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
@@ -286,15 +271,6 @@ export const HistoryProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                    updateHistory: false,
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            addNotes: ({ undoData: { noteIds } }) => {
 | 
			
		||||
                return removeNotes(noteIds, { updateHistory: false });
 | 
			
		||||
            },
 | 
			
		||||
            removeNotes: ({ undoData: { notes } }) => {
 | 
			
		||||
                return addNotes(notes, { updateHistory: false });
 | 
			
		||||
            },
 | 
			
		||||
            updateNote: ({ undoData: { noteId, note } }) => {
 | 
			
		||||
                return updateNote(noteId, note, { updateHistory: false });
 | 
			
		||||
            },
 | 
			
		||||
        }),
 | 
			
		||||
        [
 | 
			
		||||
            addTables,
 | 
			
		||||
@@ -320,9 +296,6 @@ export const HistoryProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            addCustomTypes,
 | 
			
		||||
            removeCustomTypes,
 | 
			
		||||
            updateCustomType,
 | 
			
		||||
            addNotes,
 | 
			
		||||
            removeNotes,
 | 
			
		||||
            updateNote,
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@ import type { DBRelationship } from '@/lib/domain/db-relationship';
 | 
			
		||||
import type { DBDependency } from '@/lib/domain/db-dependency';
 | 
			
		||||
import type { Area } from '@/lib/domain/area';
 | 
			
		||||
import type { DBCustomType } from '@/lib/domain/db-custom-type';
 | 
			
		||||
import type { Note } from '@/lib/domain/note';
 | 
			
		||||
 | 
			
		||||
type Action = keyof ChartDBContext;
 | 
			
		||||
 | 
			
		||||
@@ -162,24 +161,6 @@ type RedoUndoActionRemoveCustomTypes = RedoUndoActionBase<
 | 
			
		||||
    { customTypes: DBCustomType[] }
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
type RedoUndoActionAddNotes = RedoUndoActionBase<
 | 
			
		||||
    'addNotes',
 | 
			
		||||
    { notes: Note[] },
 | 
			
		||||
    { noteIds: string[] }
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
type RedoUndoActionUpdateNote = RedoUndoActionBase<
 | 
			
		||||
    'updateNote',
 | 
			
		||||
    { noteId: string; note: Partial<Note> },
 | 
			
		||||
    { noteId: string; note: Partial<Note> }
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
type RedoUndoActionRemoveNotes = RedoUndoActionBase<
 | 
			
		||||
    'removeNotes',
 | 
			
		||||
    { noteIds: string[] },
 | 
			
		||||
    { notes: Note[] }
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
export type RedoUndoAction =
 | 
			
		||||
    | RedoUndoActionAddTables
 | 
			
		||||
    | RedoUndoActionRemoveTables
 | 
			
		||||
@@ -203,10 +184,7 @@ export type RedoUndoAction =
 | 
			
		||||
    | RedoUndoActionRemoveAreas
 | 
			
		||||
    | RedoUndoActionAddCustomTypes
 | 
			
		||||
    | RedoUndoActionUpdateCustomType
 | 
			
		||||
    | RedoUndoActionRemoveCustomTypes
 | 
			
		||||
    | RedoUndoActionAddNotes
 | 
			
		||||
    | RedoUndoActionUpdateNote
 | 
			
		||||
    | RedoUndoActionRemoveNotes;
 | 
			
		||||
    | RedoUndoActionRemoveCustomTypes;
 | 
			
		||||
 | 
			
		||||
export type RedoActionData<T extends Action> = Extract<
 | 
			
		||||
    RedoUndoAction,
 | 
			
		||||
 
 | 
			
		||||
@@ -2,37 +2,29 @@ import { emptyFn } from '@/lib/utils';
 | 
			
		||||
import { createContext } from 'react';
 | 
			
		||||
 | 
			
		||||
export type SidebarSection =
 | 
			
		||||
    | 'dbml'
 | 
			
		||||
    | 'tables'
 | 
			
		||||
    | 'refs'
 | 
			
		||||
    | 'customTypes'
 | 
			
		||||
    | 'visuals';
 | 
			
		||||
 | 
			
		||||
export type VisualsTab = 'areas' | 'notes';
 | 
			
		||||
    | 'relationships'
 | 
			
		||||
    | 'dependencies'
 | 
			
		||||
    | 'areas'
 | 
			
		||||
    | 'customTypes';
 | 
			
		||||
 | 
			
		||||
export interface LayoutContext {
 | 
			
		||||
    openedTableInSidebar: string | undefined;
 | 
			
		||||
    openTableFromSidebar: (tableId: string) => void;
 | 
			
		||||
    closeAllTablesInSidebar: () => void;
 | 
			
		||||
 | 
			
		||||
    openedRelationshipInSidebar: string | undefined;
 | 
			
		||||
    openRelationshipFromSidebar: (relationshipId: string) => void;
 | 
			
		||||
    closeAllRelationshipsInSidebar: () => void;
 | 
			
		||||
 | 
			
		||||
    openedDependencyInSidebar: string | undefined;
 | 
			
		||||
    openDependencyFromSidebar: (dependencyId: string) => void;
 | 
			
		||||
    closeAllDependenciesInSidebar: () => void;
 | 
			
		||||
 | 
			
		||||
    openedRefInSidebar: string | undefined;
 | 
			
		||||
    openRefFromSidebar: (refId: string) => void;
 | 
			
		||||
    closeAllRefsInSidebar: () => void;
 | 
			
		||||
 | 
			
		||||
    openedAreaInSidebar: string | undefined;
 | 
			
		||||
    openAreaFromSidebar: (areaId: string) => void;
 | 
			
		||||
    closeAllAreasInSidebar: () => void;
 | 
			
		||||
 | 
			
		||||
    openedNoteInSidebar: string | undefined;
 | 
			
		||||
    openNoteFromSidebar: (noteId: string) => void;
 | 
			
		||||
    closeAllNotesInSidebar: () => void;
 | 
			
		||||
 | 
			
		||||
    openedCustomTypeInSidebar: string | undefined;
 | 
			
		||||
    openCustomTypeFromSidebar: (customTypeId: string) => void;
 | 
			
		||||
    closeAllCustomTypesInSidebar: () => void;
 | 
			
		||||
@@ -40,37 +32,32 @@ export interface LayoutContext {
 | 
			
		||||
    selectedSidebarSection: SidebarSection;
 | 
			
		||||
    selectSidebarSection: (section: SidebarSection) => void;
 | 
			
		||||
 | 
			
		||||
    selectedVisualsTab: VisualsTab;
 | 
			
		||||
    selectVisualsTab: (tab: VisualsTab) => void;
 | 
			
		||||
 | 
			
		||||
    isSidePanelShowed: boolean;
 | 
			
		||||
    hideSidePanel: () => void;
 | 
			
		||||
    showSidePanel: () => void;
 | 
			
		||||
    toggleSidePanel: () => void;
 | 
			
		||||
 | 
			
		||||
    isSelectSchemaOpen: boolean;
 | 
			
		||||
    openSelectSchema: () => void;
 | 
			
		||||
    closeSelectSchema: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const layoutContext = createContext<LayoutContext>({
 | 
			
		||||
    openedTableInSidebar: undefined,
 | 
			
		||||
    selectedSidebarSection: 'tables',
 | 
			
		||||
 | 
			
		||||
    openedRelationshipInSidebar: undefined,
 | 
			
		||||
    openRelationshipFromSidebar: emptyFn,
 | 
			
		||||
    closeAllRelationshipsInSidebar: emptyFn,
 | 
			
		||||
 | 
			
		||||
    openedDependencyInSidebar: undefined,
 | 
			
		||||
    openDependencyFromSidebar: emptyFn,
 | 
			
		||||
    closeAllDependenciesInSidebar: emptyFn,
 | 
			
		||||
 | 
			
		||||
    openedRefInSidebar: undefined,
 | 
			
		||||
    openRefFromSidebar: emptyFn,
 | 
			
		||||
    closeAllRefsInSidebar: emptyFn,
 | 
			
		||||
 | 
			
		||||
    openedAreaInSidebar: undefined,
 | 
			
		||||
    openAreaFromSidebar: emptyFn,
 | 
			
		||||
    closeAllAreasInSidebar: emptyFn,
 | 
			
		||||
 | 
			
		||||
    openedNoteInSidebar: undefined,
 | 
			
		||||
    openNoteFromSidebar: emptyFn,
 | 
			
		||||
    closeAllNotesInSidebar: emptyFn,
 | 
			
		||||
 | 
			
		||||
    openedCustomTypeInSidebar: undefined,
 | 
			
		||||
    openCustomTypeFromSidebar: emptyFn,
 | 
			
		||||
    closeAllCustomTypesInSidebar: emptyFn,
 | 
			
		||||
@@ -79,11 +66,12 @@ export const layoutContext = createContext<LayoutContext>({
 | 
			
		||||
    openTableFromSidebar: emptyFn,
 | 
			
		||||
    closeAllTablesInSidebar: emptyFn,
 | 
			
		||||
 | 
			
		||||
    selectedVisualsTab: 'areas',
 | 
			
		||||
    selectVisualsTab: emptyFn,
 | 
			
		||||
 | 
			
		||||
    isSidePanelShowed: false,
 | 
			
		||||
    hideSidePanel: emptyFn,
 | 
			
		||||
    showSidePanel: emptyFn,
 | 
			
		||||
    toggleSidePanel: emptyFn,
 | 
			
		||||
 | 
			
		||||
    isSelectSchemaOpen: false,
 | 
			
		||||
    openSelectSchema: emptyFn,
 | 
			
		||||
    closeSelectSchema: emptyFn,
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,5 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import type {
 | 
			
		||||
    LayoutContext,
 | 
			
		||||
    SidebarSection,
 | 
			
		||||
    VisualsTab,
 | 
			
		||||
} from './layout-context';
 | 
			
		||||
import type { LayoutContext, SidebarSection } from './layout-context';
 | 
			
		||||
import { layoutContext } from './layout-context';
 | 
			
		||||
import { useBreakpoint } from '@/hooks/use-breakpoint';
 | 
			
		||||
 | 
			
		||||
@@ -14,42 +10,34 @@ export const LayoutProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    const [openedTableInSidebar, setOpenedTableInSidebar] = React.useState<
 | 
			
		||||
        string | undefined
 | 
			
		||||
    >();
 | 
			
		||||
    const [openedRefInSidebar, setOpenedRefInSidebar] = React.useState<
 | 
			
		||||
        string | undefined
 | 
			
		||||
    >();
 | 
			
		||||
    const [openedRelationshipInSidebar, setOpenedRelationshipInSidebar] =
 | 
			
		||||
        React.useState<string | undefined>();
 | 
			
		||||
    const [openedDependencyInSidebar, setOpenedDependencyInSidebar] =
 | 
			
		||||
        React.useState<string | undefined>();
 | 
			
		||||
    const [openedAreaInSidebar, setOpenedAreaInSidebar] = React.useState<
 | 
			
		||||
        string | undefined
 | 
			
		||||
    >();
 | 
			
		||||
    const [openedNoteInSidebar, setOpenedNoteInSidebar] = React.useState<
 | 
			
		||||
        string | undefined
 | 
			
		||||
    >();
 | 
			
		||||
    const [openedCustomTypeInSidebar, setOpenedCustomTypeInSidebar] =
 | 
			
		||||
        React.useState<string | undefined>();
 | 
			
		||||
    const [selectedSidebarSection, setSelectedSidebarSection] =
 | 
			
		||||
        React.useState<SidebarSection>('tables');
 | 
			
		||||
    const [selectedVisualsTab, setSelectedVisualsTab] =
 | 
			
		||||
        React.useState<VisualsTab>('areas');
 | 
			
		||||
    const [isSidePanelShowed, setIsSidePanelShowed] =
 | 
			
		||||
        React.useState<boolean>(isDesktop);
 | 
			
		||||
    const [isSelectSchemaOpen, setIsSelectSchemaOpen] =
 | 
			
		||||
        React.useState<boolean>(false);
 | 
			
		||||
 | 
			
		||||
    const closeAllTablesInSidebar: LayoutContext['closeAllTablesInSidebar'] =
 | 
			
		||||
        () => setOpenedTableInSidebar('');
 | 
			
		||||
 | 
			
		||||
    const closeAllRelationshipsInSidebar: LayoutContext['closeAllRelationshipsInSidebar'] =
 | 
			
		||||
        () => setOpenedRefInSidebar('');
 | 
			
		||||
        () => setOpenedRelationshipInSidebar('');
 | 
			
		||||
 | 
			
		||||
    const closeAllDependenciesInSidebar: LayoutContext['closeAllDependenciesInSidebar'] =
 | 
			
		||||
        () => setOpenedRefInSidebar('');
 | 
			
		||||
 | 
			
		||||
    const closeAllRefsInSidebar: LayoutContext['closeAllRefsInSidebar'] = () =>
 | 
			
		||||
        setOpenedRefInSidebar('');
 | 
			
		||||
        () => setOpenedDependencyInSidebar('');
 | 
			
		||||
 | 
			
		||||
    const closeAllAreasInSidebar: LayoutContext['closeAllAreasInSidebar'] =
 | 
			
		||||
        () => setOpenedAreaInSidebar('');
 | 
			
		||||
 | 
			
		||||
    const closeAllNotesInSidebar: LayoutContext['closeAllNotesInSidebar'] =
 | 
			
		||||
        () => setOpenedNoteInSidebar('');
 | 
			
		||||
 | 
			
		||||
    const closeAllCustomTypesInSidebar: LayoutContext['closeAllCustomTypesInSidebar'] =
 | 
			
		||||
        () => setOpenedCustomTypeInSidebar('');
 | 
			
		||||
 | 
			
		||||
@@ -74,41 +62,25 @@ export const LayoutProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    const openRelationshipFromSidebar: LayoutContext['openRelationshipFromSidebar'] =
 | 
			
		||||
        (relationshipId) => {
 | 
			
		||||
            showSidePanel();
 | 
			
		||||
            setSelectedSidebarSection('refs');
 | 
			
		||||
            setOpenedRefInSidebar(relationshipId);
 | 
			
		||||
            setSelectedSidebarSection('relationships');
 | 
			
		||||
            setOpenedRelationshipInSidebar(relationshipId);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    const openDependencyFromSidebar: LayoutContext['openDependencyFromSidebar'] =
 | 
			
		||||
        (dependencyId) => {
 | 
			
		||||
            showSidePanel();
 | 
			
		||||
            setSelectedSidebarSection('refs');
 | 
			
		||||
            setOpenedRefInSidebar(dependencyId);
 | 
			
		||||
            setSelectedSidebarSection('dependencies');
 | 
			
		||||
            setOpenedDependencyInSidebar(dependencyId);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    const openRefFromSidebar: LayoutContext['openRefFromSidebar'] = (refId) => {
 | 
			
		||||
        showSidePanel();
 | 
			
		||||
        setSelectedSidebarSection('refs');
 | 
			
		||||
        setOpenedRefInSidebar(refId);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const openAreaFromSidebar: LayoutContext['openAreaFromSidebar'] = (
 | 
			
		||||
        areaId
 | 
			
		||||
    ) => {
 | 
			
		||||
        showSidePanel();
 | 
			
		||||
        setSelectedSidebarSection('visuals');
 | 
			
		||||
        setSelectedVisualsTab('areas');
 | 
			
		||||
        setSelectedSidebarSection('areas');
 | 
			
		||||
        setOpenedAreaInSidebar(areaId);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const openNoteFromSidebar: LayoutContext['openNoteFromSidebar'] = (
 | 
			
		||||
        noteId
 | 
			
		||||
    ) => {
 | 
			
		||||
        showSidePanel();
 | 
			
		||||
        setSelectedSidebarSection('visuals');
 | 
			
		||||
        setSelectedVisualsTab('notes');
 | 
			
		||||
        setOpenedNoteInSidebar(noteId);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const openCustomTypeFromSidebar: LayoutContext['openCustomTypeFromSidebar'] =
 | 
			
		||||
        (customTypeId) => {
 | 
			
		||||
            showSidePanel();
 | 
			
		||||
@@ -116,6 +88,11 @@ export const LayoutProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            setOpenedTableInSidebar(customTypeId);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    const openSelectSchema: LayoutContext['openSelectSchema'] = () =>
 | 
			
		||||
        setIsSelectSchemaOpen(true);
 | 
			
		||||
 | 
			
		||||
    const closeSelectSchema: LayoutContext['closeSelectSchema'] = () =>
 | 
			
		||||
        setIsSelectSchemaOpen(false);
 | 
			
		||||
    return (
 | 
			
		||||
        <layoutContext.Provider
 | 
			
		||||
            value={{
 | 
			
		||||
@@ -123,6 +100,7 @@ export const LayoutProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                selectedSidebarSection,
 | 
			
		||||
                openTableFromSidebar,
 | 
			
		||||
                selectSidebarSection: setSelectedSidebarSection,
 | 
			
		||||
                openedRelationshipInSidebar,
 | 
			
		||||
                openRelationshipFromSidebar,
 | 
			
		||||
                closeAllTablesInSidebar,
 | 
			
		||||
                closeAllRelationshipsInSidebar,
 | 
			
		||||
@@ -130,22 +108,18 @@ export const LayoutProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                hideSidePanel,
 | 
			
		||||
                showSidePanel,
 | 
			
		||||
                toggleSidePanel,
 | 
			
		||||
                isSelectSchemaOpen,
 | 
			
		||||
                openSelectSchema,
 | 
			
		||||
                closeSelectSchema,
 | 
			
		||||
                openedDependencyInSidebar,
 | 
			
		||||
                openDependencyFromSidebar,
 | 
			
		||||
                closeAllDependenciesInSidebar,
 | 
			
		||||
                openedRefInSidebar,
 | 
			
		||||
                openRefFromSidebar,
 | 
			
		||||
                closeAllRefsInSidebar,
 | 
			
		||||
                openedAreaInSidebar,
 | 
			
		||||
                openAreaFromSidebar,
 | 
			
		||||
                closeAllAreasInSidebar,
 | 
			
		||||
                openedNoteInSidebar,
 | 
			
		||||
                openNoteFromSidebar,
 | 
			
		||||
                closeAllNotesInSidebar,
 | 
			
		||||
                openedCustomTypeInSidebar,
 | 
			
		||||
                openCustomTypeFromSidebar,
 | 
			
		||||
                closeAllCustomTypesInSidebar,
 | 
			
		||||
                selectedVisualsTab,
 | 
			
		||||
                selectVisualsTab: setSelectedVisualsTab,
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            {children}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ import type { Theme } from '../theme-context/theme-context';
 | 
			
		||||
 | 
			
		||||
export type ScrollAction = 'pan' | 'zoom';
 | 
			
		||||
 | 
			
		||||
export type SchemasFilter = Record<string, string[]>;
 | 
			
		||||
 | 
			
		||||
export interface LocalConfigContext {
 | 
			
		||||
    theme: Theme;
 | 
			
		||||
    setTheme: (theme: Theme) => void;
 | 
			
		||||
@@ -11,14 +13,16 @@ export interface LocalConfigContext {
 | 
			
		||||
    scrollAction: ScrollAction;
 | 
			
		||||
    setScrollAction: (action: ScrollAction) => void;
 | 
			
		||||
 | 
			
		||||
    showDBViews: boolean;
 | 
			
		||||
    setShowDBViews: (showViews: boolean) => void;
 | 
			
		||||
    schemasFilter: SchemasFilter;
 | 
			
		||||
    setSchemasFilter: React.Dispatch<React.SetStateAction<SchemasFilter>>;
 | 
			
		||||
 | 
			
		||||
    showCardinality: boolean;
 | 
			
		||||
    setShowCardinality: (showCardinality: boolean) => void;
 | 
			
		||||
 | 
			
		||||
    showFieldAttributes: boolean;
 | 
			
		||||
    setShowFieldAttributes: (showFieldAttributes: boolean) => void;
 | 
			
		||||
    hideMultiSchemaNotification: boolean;
 | 
			
		||||
    setHideMultiSchemaNotification: (
 | 
			
		||||
        hideMultiSchemaNotification: boolean
 | 
			
		||||
    ) => void;
 | 
			
		||||
 | 
			
		||||
    githubRepoOpened: boolean;
 | 
			
		||||
    setGithubRepoOpened: (githubRepoOpened: boolean) => void;
 | 
			
		||||
@@ -26,6 +30,9 @@ export interface LocalConfigContext {
 | 
			
		||||
    starUsDialogLastOpen: number;
 | 
			
		||||
    setStarUsDialogLastOpen: (lastOpen: number) => void;
 | 
			
		||||
 | 
			
		||||
    showDependenciesOnCanvas: boolean;
 | 
			
		||||
    setShowDependenciesOnCanvas: (showDependenciesOnCanvas: boolean) => void;
 | 
			
		||||
 | 
			
		||||
    showMiniMapOnCanvas: boolean;
 | 
			
		||||
    setShowMiniMapOnCanvas: (showMiniMapOnCanvas: boolean) => void;
 | 
			
		||||
}
 | 
			
		||||
@@ -37,14 +44,14 @@ export const LocalConfigContext = createContext<LocalConfigContext>({
 | 
			
		||||
    scrollAction: 'pan',
 | 
			
		||||
    setScrollAction: emptyFn,
 | 
			
		||||
 | 
			
		||||
    showDBViews: false,
 | 
			
		||||
    setShowDBViews: emptyFn,
 | 
			
		||||
    schemasFilter: {},
 | 
			
		||||
    setSchemasFilter: emptyFn,
 | 
			
		||||
 | 
			
		||||
    showCardinality: true,
 | 
			
		||||
    setShowCardinality: emptyFn,
 | 
			
		||||
 | 
			
		||||
    showFieldAttributes: true,
 | 
			
		||||
    setShowFieldAttributes: emptyFn,
 | 
			
		||||
    hideMultiSchemaNotification: false,
 | 
			
		||||
    setHideMultiSchemaNotification: emptyFn,
 | 
			
		||||
 | 
			
		||||
    githubRepoOpened: false,
 | 
			
		||||
    setGithubRepoOpened: emptyFn,
 | 
			
		||||
@@ -52,6 +59,9 @@ export const LocalConfigContext = createContext<LocalConfigContext>({
 | 
			
		||||
    starUsDialogLastOpen: 0,
 | 
			
		||||
    setStarUsDialogLastOpen: emptyFn,
 | 
			
		||||
 | 
			
		||||
    showDependenciesOnCanvas: false,
 | 
			
		||||
    setShowDependenciesOnCanvas: emptyFn,
 | 
			
		||||
 | 
			
		||||
    showMiniMapOnCanvas: false,
 | 
			
		||||
    setShowMiniMapOnCanvas: emptyFn,
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,17 @@
 | 
			
		||||
import React, { useEffect } from 'react';
 | 
			
		||||
import type { ScrollAction } from './local-config-context';
 | 
			
		||||
import type { SchemasFilter, ScrollAction } from './local-config-context';
 | 
			
		||||
import { LocalConfigContext } from './local-config-context';
 | 
			
		||||
import type { Theme } from '../theme-context/theme-context';
 | 
			
		||||
 | 
			
		||||
const themeKey = 'theme';
 | 
			
		||||
const scrollActionKey = 'scroll_action';
 | 
			
		||||
const schemasFilterKey = 'schemas_filter';
 | 
			
		||||
const showCardinalityKey = 'show_cardinality';
 | 
			
		||||
const showFieldAttributesKey = 'show_field_attributes';
 | 
			
		||||
const hideMultiSchemaNotificationKey = 'hide_multi_schema_notification';
 | 
			
		||||
const githubRepoOpenedKey = 'github_repo_opened';
 | 
			
		||||
const starUsDialogLastOpenKey = 'star_us_dialog_last_open';
 | 
			
		||||
const showDependenciesOnCanvasKey = 'show_dependencies_on_canvas';
 | 
			
		||||
const showMiniMapOnCanvasKey = 'show_minimap_on_canvas';
 | 
			
		||||
const showDBViewsKey = 'show_db_views';
 | 
			
		||||
 | 
			
		||||
export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    children,
 | 
			
		||||
@@ -23,17 +24,20 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
        (localStorage.getItem(scrollActionKey) as ScrollAction) || 'pan'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const [showDBViews, setShowDBViews] = React.useState<boolean>(
 | 
			
		||||
        (localStorage.getItem(showDBViewsKey) || 'false') === 'true'
 | 
			
		||||
    const [schemasFilter, setSchemasFilter] = React.useState<SchemasFilter>(
 | 
			
		||||
        JSON.parse(
 | 
			
		||||
            localStorage.getItem(schemasFilterKey) || '{}'
 | 
			
		||||
        ) as SchemasFilter
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const [showCardinality, setShowCardinality] = React.useState<boolean>(
 | 
			
		||||
        (localStorage.getItem(showCardinalityKey) || 'true') === 'true'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const [showFieldAttributes, setShowFieldAttributes] =
 | 
			
		||||
    const [hideMultiSchemaNotification, setHideMultiSchemaNotification] =
 | 
			
		||||
        React.useState<boolean>(
 | 
			
		||||
            (localStorage.getItem(showFieldAttributesKey) || 'true') === 'true'
 | 
			
		||||
            (localStorage.getItem(hideMultiSchemaNotificationKey) ||
 | 
			
		||||
                'false') === 'true'
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const [githubRepoOpened, setGithubRepoOpened] = React.useState<boolean>(
 | 
			
		||||
@@ -45,6 +49,12 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            parseInt(localStorage.getItem(starUsDialogLastOpenKey) || '0')
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const [showDependenciesOnCanvas, setShowDependenciesOnCanvas] =
 | 
			
		||||
        React.useState<boolean>(
 | 
			
		||||
            (localStorage.getItem(showDependenciesOnCanvasKey) || 'false') ===
 | 
			
		||||
                'true'
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const [showMiniMapOnCanvas, setShowMiniMapOnCanvas] =
 | 
			
		||||
        React.useState<boolean>(
 | 
			
		||||
            (localStorage.getItem(showMiniMapOnCanvasKey) || 'true') === 'true'
 | 
			
		||||
@@ -61,6 +71,13 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
        localStorage.setItem(githubRepoOpenedKey, githubRepoOpened.toString());
 | 
			
		||||
    }, [githubRepoOpened]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        localStorage.setItem(
 | 
			
		||||
            hideMultiSchemaNotificationKey,
 | 
			
		||||
            hideMultiSchemaNotification.toString()
 | 
			
		||||
        );
 | 
			
		||||
    }, [hideMultiSchemaNotification]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        localStorage.setItem(themeKey, theme);
 | 
			
		||||
    }, [theme]);
 | 
			
		||||
@@ -70,13 +87,20 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    }, [scrollAction]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        localStorage.setItem(showDBViewsKey, showDBViews.toString());
 | 
			
		||||
    }, [showDBViews]);
 | 
			
		||||
        localStorage.setItem(schemasFilterKey, JSON.stringify(schemasFilter));
 | 
			
		||||
    }, [schemasFilter]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        localStorage.setItem(showCardinalityKey, showCardinality.toString());
 | 
			
		||||
    }, [showCardinality]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        localStorage.setItem(
 | 
			
		||||
            showDependenciesOnCanvasKey,
 | 
			
		||||
            showDependenciesOnCanvas.toString()
 | 
			
		||||
        );
 | 
			
		||||
    }, [showDependenciesOnCanvas]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        localStorage.setItem(
 | 
			
		||||
            showMiniMapOnCanvasKey,
 | 
			
		||||
@@ -91,16 +115,18 @@ export const LocalConfigProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                setTheme,
 | 
			
		||||
                scrollAction,
 | 
			
		||||
                setScrollAction,
 | 
			
		||||
                showDBViews,
 | 
			
		||||
                setShowDBViews,
 | 
			
		||||
                schemasFilter,
 | 
			
		||||
                setSchemasFilter,
 | 
			
		||||
                showCardinality,
 | 
			
		||||
                setShowCardinality,
 | 
			
		||||
                showFieldAttributes,
 | 
			
		||||
                setShowFieldAttributes,
 | 
			
		||||
                hideMultiSchemaNotification,
 | 
			
		||||
                setHideMultiSchemaNotification,
 | 
			
		||||
                setGithubRepoOpened,
 | 
			
		||||
                githubRepoOpened,
 | 
			
		||||
                starUsDialogLastOpen,
 | 
			
		||||
                setStarUsDialogLastOpen,
 | 
			
		||||
                showDependenciesOnCanvas,
 | 
			
		||||
                setShowDependenciesOnCanvas,
 | 
			
		||||
                showMiniMapOnCanvas,
 | 
			
		||||
                setShowMiniMapOnCanvas,
 | 
			
		||||
            }}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,22 +7,12 @@ import type { ChartDBConfig } from '@/lib/domain/config';
 | 
			
		||||
import type { DBDependency } from '@/lib/domain/db-dependency';
 | 
			
		||||
import type { Area } from '@/lib/domain/area';
 | 
			
		||||
import type { DBCustomType } from '@/lib/domain/db-custom-type';
 | 
			
		||||
import type { DiagramFilter } from '@/lib/domain/diagram-filter/diagram-filter';
 | 
			
		||||
import type { Note } from '@/lib/domain/note';
 | 
			
		||||
 | 
			
		||||
export interface StorageContext {
 | 
			
		||||
    // Config operations
 | 
			
		||||
    getConfig: () => Promise<ChartDBConfig | undefined>;
 | 
			
		||||
    updateConfig: (config: Partial<ChartDBConfig>) => Promise<void>;
 | 
			
		||||
 | 
			
		||||
    // Diagram filter operations
 | 
			
		||||
    getDiagramFilter: (diagramId: string) => Promise<DiagramFilter | undefined>;
 | 
			
		||||
    updateDiagramFilter: (
 | 
			
		||||
        diagramId: string,
 | 
			
		||||
        filter: DiagramFilter
 | 
			
		||||
    ) => Promise<void>;
 | 
			
		||||
    deleteDiagramFilter: (diagramId: string) => Promise<void>;
 | 
			
		||||
 | 
			
		||||
    // Diagram operations
 | 
			
		||||
    addDiagram: (params: { diagram: Diagram }) => Promise<void>;
 | 
			
		||||
    listDiagrams: (options?: {
 | 
			
		||||
@@ -31,7 +21,6 @@ export interface StorageContext {
 | 
			
		||||
        includeDependencies?: boolean;
 | 
			
		||||
        includeAreas?: boolean;
 | 
			
		||||
        includeCustomTypes?: boolean;
 | 
			
		||||
        includeNotes?: boolean;
 | 
			
		||||
    }) => Promise<Diagram[]>;
 | 
			
		||||
    getDiagram: (
 | 
			
		||||
        id: string,
 | 
			
		||||
@@ -41,7 +30,6 @@ export interface StorageContext {
 | 
			
		||||
            includeDependencies?: boolean;
 | 
			
		||||
            includeAreas?: boolean;
 | 
			
		||||
            includeCustomTypes?: boolean;
 | 
			
		||||
            includeNotes?: boolean;
 | 
			
		||||
        }
 | 
			
		||||
    ) => Promise<Diagram | undefined>;
 | 
			
		||||
    updateDiagram: (params: {
 | 
			
		||||
@@ -138,30 +126,12 @@ export interface StorageContext {
 | 
			
		||||
    }) => Promise<void>;
 | 
			
		||||
    listCustomTypes: (diagramId: string) => Promise<DBCustomType[]>;
 | 
			
		||||
    deleteDiagramCustomTypes: (diagramId: string) => Promise<void>;
 | 
			
		||||
 | 
			
		||||
    // Note operations
 | 
			
		||||
    addNote: (params: { diagramId: string; note: Note }) => Promise<void>;
 | 
			
		||||
    getNote: (params: {
 | 
			
		||||
        diagramId: string;
 | 
			
		||||
        id: string;
 | 
			
		||||
    }) => Promise<Note | undefined>;
 | 
			
		||||
    updateNote: (params: {
 | 
			
		||||
        id: string;
 | 
			
		||||
        attributes: Partial<Note>;
 | 
			
		||||
    }) => Promise<void>;
 | 
			
		||||
    deleteNote: (params: { diagramId: string; id: string }) => Promise<void>;
 | 
			
		||||
    listNotes: (diagramId: string) => Promise<Note[]>;
 | 
			
		||||
    deleteDiagramNotes: (diagramId: string) => Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const storageInitialValue: StorageContext = {
 | 
			
		||||
    getConfig: emptyFn,
 | 
			
		||||
    updateConfig: emptyFn,
 | 
			
		||||
 | 
			
		||||
    getDiagramFilter: emptyFn,
 | 
			
		||||
    updateDiagramFilter: emptyFn,
 | 
			
		||||
    deleteDiagramFilter: emptyFn,
 | 
			
		||||
 | 
			
		||||
    addDiagram: emptyFn,
 | 
			
		||||
    listDiagrams: emptyFn,
 | 
			
		||||
    getDiagram: emptyFn,
 | 
			
		||||
@@ -204,14 +174,6 @@ export const storageInitialValue: StorageContext = {
 | 
			
		||||
    deleteCustomType: emptyFn,
 | 
			
		||||
    listCustomTypes: emptyFn,
 | 
			
		||||
    deleteDiagramCustomTypes: emptyFn,
 | 
			
		||||
 | 
			
		||||
    // Note operations
 | 
			
		||||
    addNote: emptyFn,
 | 
			
		||||
    getNote: emptyFn,
 | 
			
		||||
    updateNote: emptyFn,
 | 
			
		||||
    deleteNote: emptyFn,
 | 
			
		||||
    listNotes: emptyFn,
 | 
			
		||||
    deleteDiagramNotes: emptyFn,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const storageContext =
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,6 @@ import type { ChartDBConfig } from '@/lib/domain/config';
 | 
			
		||||
import type { DBDependency } from '@/lib/domain/db-dependency';
 | 
			
		||||
import type { Area } from '@/lib/domain/area';
 | 
			
		||||
import type { DBCustomType } from '@/lib/domain/db-custom-type';
 | 
			
		||||
import type { DiagramFilter } from '@/lib/domain/diagram-filter/diagram-filter';
 | 
			
		||||
import type { Note } from '@/lib/domain/note';
 | 
			
		||||
 | 
			
		||||
export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
    children,
 | 
			
		||||
@@ -42,18 +40,10 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                DBCustomType & { diagramId: string },
 | 
			
		||||
                'id' // primary key "id" (for the typings only)
 | 
			
		||||
            >;
 | 
			
		||||
            notes: EntityTable<
 | 
			
		||||
                Note & { diagramId: string },
 | 
			
		||||
                'id' // primary key "id" (for the typings only)
 | 
			
		||||
            >;
 | 
			
		||||
            config: EntityTable<
 | 
			
		||||
                ChartDBConfig & { id: number },
 | 
			
		||||
                'id' // primary key "id" (for the typings only)
 | 
			
		||||
            >;
 | 
			
		||||
            diagram_filters: EntityTable<
 | 
			
		||||
                DiagramFilter & { diagramId: string },
 | 
			
		||||
                'diagramId' // primary key "id" (for the typings only)
 | 
			
		||||
            >;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Schema declaration:
 | 
			
		||||
@@ -200,44 +190,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            config: '++id, defaultDiagramId',
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        dexieDB
 | 
			
		||||
            .version(12)
 | 
			
		||||
            .stores({
 | 
			
		||||
                diagrams:
 | 
			
		||||
                    '++id, name, databaseType, databaseEdition, createdAt, updatedAt',
 | 
			
		||||
                db_tables:
 | 
			
		||||
                    '++id, diagramId, name, schema, x, y, fields, indexes, color, createdAt, width, comment, isView, isMaterializedView, order',
 | 
			
		||||
                db_relationships:
 | 
			
		||||
                    '++id, diagramId, name, sourceSchema, sourceTableId, targetSchema, targetTableId, sourceFieldId, targetFieldId, type, createdAt',
 | 
			
		||||
                db_dependencies:
 | 
			
		||||
                    '++id, diagramId, schema, tableId, dependentSchema, dependentTableId, createdAt',
 | 
			
		||||
                areas: '++id, diagramId, name, x, y, width, height, color',
 | 
			
		||||
                db_custom_types:
 | 
			
		||||
                    '++id, diagramId, schema, type, kind, values, fields',
 | 
			
		||||
                config: '++id, defaultDiagramId',
 | 
			
		||||
                diagram_filters: 'diagramId, tableIds, schemasIds',
 | 
			
		||||
            })
 | 
			
		||||
            .upgrade((tx) => {
 | 
			
		||||
                tx.table('config').clear();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        dexieDB.version(13).stores({
 | 
			
		||||
            diagrams:
 | 
			
		||||
                '++id, name, databaseType, databaseEdition, createdAt, updatedAt',
 | 
			
		||||
            db_tables:
 | 
			
		||||
                '++id, diagramId, name, schema, x, y, fields, indexes, color, createdAt, width, comment, isView, isMaterializedView, order',
 | 
			
		||||
            db_relationships:
 | 
			
		||||
                '++id, diagramId, name, sourceSchema, sourceTableId, targetSchema, targetTableId, sourceFieldId, targetFieldId, type, createdAt',
 | 
			
		||||
            db_dependencies:
 | 
			
		||||
                '++id, diagramId, schema, tableId, dependentSchema, dependentTableId, createdAt',
 | 
			
		||||
            areas: '++id, diagramId, name, x, y, width, height, color',
 | 
			
		||||
            db_custom_types:
 | 
			
		||||
                '++id, diagramId, schema, type, kind, values, fields',
 | 
			
		||||
            config: '++id, defaultDiagramId',
 | 
			
		||||
            diagram_filters: 'diagramId, tableIds, schemasIds',
 | 
			
		||||
            notes: '++id, diagramId, content, x, y, width, height, color',
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        dexieDB.on('ready', async () => {
 | 
			
		||||
            const config = await dexieDB.config.get(1);
 | 
			
		||||
 | 
			
		||||
@@ -265,34 +217,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
        [db]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getDiagramFilter: StorageContext['getDiagramFilter'] = useCallback(
 | 
			
		||||
        async (diagramId: string): Promise<DiagramFilter | undefined> => {
 | 
			
		||||
            const filter = await db.diagram_filters.get({ diagramId });
 | 
			
		||||
 | 
			
		||||
            return filter;
 | 
			
		||||
        },
 | 
			
		||||
        [db]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const updateDiagramFilter: StorageContext['updateDiagramFilter'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            async (diagramId, filter): Promise<void> => {
 | 
			
		||||
                await db.diagram_filters.put({
 | 
			
		||||
                    diagramId,
 | 
			
		||||
                    ...filter,
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            [db]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const deleteDiagramFilter: StorageContext['deleteDiagramFilter'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            async (diagramId: string): Promise<void> => {
 | 
			
		||||
                await db.diagram_filters.where({ diagramId }).delete();
 | 
			
		||||
            },
 | 
			
		||||
            [db]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const addTable: StorageContext['addTable'] = useCallback(
 | 
			
		||||
        async ({ diagramId, table }) => {
 | 
			
		||||
            await db.db_tables.add({
 | 
			
		||||
@@ -572,56 +496,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            [db]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    // Note operations
 | 
			
		||||
    const addNote: StorageContext['addNote'] = useCallback(
 | 
			
		||||
        async ({ note, diagramId }) => {
 | 
			
		||||
            await db.notes.add({
 | 
			
		||||
                ...note,
 | 
			
		||||
                diagramId,
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        [db]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const getNote: StorageContext['getNote'] = useCallback(
 | 
			
		||||
        async ({ diagramId, id }) => {
 | 
			
		||||
            return await db.notes.get({ id, diagramId });
 | 
			
		||||
        },
 | 
			
		||||
        [db]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const updateNote: StorageContext['updateNote'] = useCallback(
 | 
			
		||||
        async ({ id, attributes }) => {
 | 
			
		||||
            await db.notes.update(id, attributes);
 | 
			
		||||
        },
 | 
			
		||||
        [db]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const deleteNote: StorageContext['deleteNote'] = useCallback(
 | 
			
		||||
        async ({ diagramId, id }) => {
 | 
			
		||||
            await db.notes.where({ id, diagramId }).delete();
 | 
			
		||||
        },
 | 
			
		||||
        [db]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const listNotes: StorageContext['listNotes'] = useCallback(
 | 
			
		||||
        async (diagramId) => {
 | 
			
		||||
            return await db.notes
 | 
			
		||||
                .where('diagramId')
 | 
			
		||||
                .equals(diagramId)
 | 
			
		||||
                .toArray();
 | 
			
		||||
        },
 | 
			
		||||
        [db]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const deleteDiagramNotes: StorageContext['deleteDiagramNotes'] =
 | 
			
		||||
        useCallback(
 | 
			
		||||
            async (diagramId) => {
 | 
			
		||||
                await db.notes.where('diagramId').equals(diagramId).delete();
 | 
			
		||||
            },
 | 
			
		||||
            [db]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const addDiagram: StorageContext['addDiagram'] = useCallback(
 | 
			
		||||
        async ({ diagram }) => {
 | 
			
		||||
            const promises = [];
 | 
			
		||||
@@ -669,22 +543,9 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const notes = diagram.notes ?? [];
 | 
			
		||||
            promises.push(
 | 
			
		||||
                ...notes.map((note) => addNote({ diagramId: diagram.id, note }))
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            await Promise.all(promises);
 | 
			
		||||
        },
 | 
			
		||||
        [
 | 
			
		||||
            db,
 | 
			
		||||
            addArea,
 | 
			
		||||
            addCustomType,
 | 
			
		||||
            addDependency,
 | 
			
		||||
            addRelationship,
 | 
			
		||||
            addTable,
 | 
			
		||||
            addNote,
 | 
			
		||||
        ]
 | 
			
		||||
        [db, addArea, addCustomType, addDependency, addRelationship, addTable]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const listDiagrams: StorageContext['listDiagrams'] = useCallback(
 | 
			
		||||
@@ -695,7 +556,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                includeDependencies: false,
 | 
			
		||||
                includeAreas: false,
 | 
			
		||||
                includeCustomTypes: false,
 | 
			
		||||
                includeNotes: false,
 | 
			
		||||
            }
 | 
			
		||||
        ): Promise<Diagram[]> => {
 | 
			
		||||
            let diagrams = await db.diagrams.toArray();
 | 
			
		||||
@@ -749,15 +609,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (options.includeNotes) {
 | 
			
		||||
                diagrams = await Promise.all(
 | 
			
		||||
                    diagrams.map(async (diagram) => {
 | 
			
		||||
                        diagram.notes = await listNotes(diagram.id);
 | 
			
		||||
                        return diagram;
 | 
			
		||||
                    })
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return diagrams;
 | 
			
		||||
        },
 | 
			
		||||
        [
 | 
			
		||||
@@ -767,7 +618,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            listDependencies,
 | 
			
		||||
            listRelationships,
 | 
			
		||||
            listTables,
 | 
			
		||||
            listNotes,
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
@@ -780,7 +630,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                includeDependencies: false,
 | 
			
		||||
                includeAreas: false,
 | 
			
		||||
                includeCustomTypes: false,
 | 
			
		||||
                includeNotes: false,
 | 
			
		||||
            }
 | 
			
		||||
        ): Promise<Diagram | undefined> => {
 | 
			
		||||
            const diagram = await db.diagrams.get(id);
 | 
			
		||||
@@ -809,10 +658,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                diagram.customTypes = await listCustomTypes(id);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (options.includeNotes) {
 | 
			
		||||
                diagram.notes = await listNotes(id);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return diagram;
 | 
			
		||||
        },
 | 
			
		||||
        [
 | 
			
		||||
@@ -822,7 +667,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
            listDependencies,
 | 
			
		||||
            listRelationships,
 | 
			
		||||
            listTables,
 | 
			
		||||
            listNotes,
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
@@ -851,9 +695,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                        .where('diagramId')
 | 
			
		||||
                        .equals(id)
 | 
			
		||||
                        .modify({ diagramId: attributes.id }),
 | 
			
		||||
                    db.notes.where('diagramId').equals(id).modify({
 | 
			
		||||
                        diagramId: attributes.id,
 | 
			
		||||
                    }),
 | 
			
		||||
                ]);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
@@ -869,7 +710,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                db.db_dependencies.where('diagramId').equals(id).delete(),
 | 
			
		||||
                db.areas.where('diagramId').equals(id).delete(),
 | 
			
		||||
                db.db_custom_types.where('diagramId').equals(id).delete(),
 | 
			
		||||
                db.notes.where('diagramId').equals(id).delete(),
 | 
			
		||||
            ]);
 | 
			
		||||
        },
 | 
			
		||||
        [db]
 | 
			
		||||
@@ -916,15 +756,6 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
			
		||||
                deleteCustomType,
 | 
			
		||||
                listCustomTypes,
 | 
			
		||||
                deleteDiagramCustomTypes,
 | 
			
		||||
                addNote,
 | 
			
		||||
                getNote,
 | 
			
		||||
                updateNote,
 | 
			
		||||
                deleteNote,
 | 
			
		||||
                listNotes,
 | 
			
		||||
                deleteDiagramNotes,
 | 
			
		||||
                getDiagramFilter,
 | 
			
		||||
                updateDiagramFilter,
 | 
			
		||||
                deleteDiagramFilter,
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            {children}
 | 
			
		||||
 
 | 
			
		||||
@@ -42,14 +42,6 @@ import {
 | 
			
		||||
    type ValidationResult,
 | 
			
		||||
} from '@/lib/data/sql-import/sql-validator';
 | 
			
		||||
import { SQLValidationStatus } from './sql-validation-status';
 | 
			
		||||
import { setupDBMLLanguage } from '@/components/code-snippet/languages/dbml-language';
 | 
			
		||||
import type { ImportMethod } from '@/lib/import-method/import-method';
 | 
			
		||||
import { detectImportMethod } from '@/lib/import-method/detect-import-method';
 | 
			
		||||
import { verifyDBML } from '@/lib/dbml/dbml-import/verify-dbml';
 | 
			
		||||
import {
 | 
			
		||||
    clearErrorHighlight,
 | 
			
		||||
    highlightErrorLine,
 | 
			
		||||
} from '@/components/code-snippet/dbml/utils';
 | 
			
		||||
 | 
			
		||||
const calculateContentSizeMB = (content: string): number => {
 | 
			
		||||
    return content.length / (1024 * 1024); // Convert to MB
 | 
			
		||||
@@ -63,6 +55,49 @@ const calculateIsLargeFile = (content: string): boolean => {
 | 
			
		||||
const errorScriptOutputMessage =
 | 
			
		||||
    'Invalid JSON. Please correct it or contact us at support@chartdb.io for help.';
 | 
			
		||||
 | 
			
		||||
// Helper to detect if content is likely SQL DDL or JSON
 | 
			
		||||
const detectContentType = (content: string): 'query' | 'ddl' | null => {
 | 
			
		||||
    if (!content || content.trim().length === 0) return null;
 | 
			
		||||
 | 
			
		||||
    // Common SQL DDL keywords
 | 
			
		||||
    const ddlKeywords = [
 | 
			
		||||
        'CREATE TABLE',
 | 
			
		||||
        'ALTER TABLE',
 | 
			
		||||
        'DROP TABLE',
 | 
			
		||||
        'CREATE INDEX',
 | 
			
		||||
        'CREATE VIEW',
 | 
			
		||||
        'CREATE PROCEDURE',
 | 
			
		||||
        'CREATE FUNCTION',
 | 
			
		||||
        'CREATE SCHEMA',
 | 
			
		||||
        'CREATE DATABASE',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const upperContent = content.toUpperCase();
 | 
			
		||||
 | 
			
		||||
    // Check for SQL DDL patterns
 | 
			
		||||
    const hasDDLKeywords = ddlKeywords.some((keyword) =>
 | 
			
		||||
        upperContent.includes(keyword)
 | 
			
		||||
    );
 | 
			
		||||
    if (hasDDLKeywords) return 'ddl';
 | 
			
		||||
 | 
			
		||||
    // Check if it looks like JSON
 | 
			
		||||
    try {
 | 
			
		||||
        // Just check structure, don't need full parse for detection
 | 
			
		||||
        if (
 | 
			
		||||
            (content.trim().startsWith('{') && content.trim().endsWith('}')) ||
 | 
			
		||||
            (content.trim().startsWith('[') && content.trim().endsWith(']'))
 | 
			
		||||
        ) {
 | 
			
		||||
            return 'query';
 | 
			
		||||
        }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        // Not valid JSON, might be partial
 | 
			
		||||
        console.error('Error detecting content type:', error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If we can't confidently detect, return null
 | 
			
		||||
    return null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface ImportDatabaseProps {
 | 
			
		||||
    goBack?: () => void;
 | 
			
		||||
    onImport: () => void;
 | 
			
		||||
@@ -76,8 +111,8 @@ export interface ImportDatabaseProps {
 | 
			
		||||
    >;
 | 
			
		||||
    keepDialogAfterImport?: boolean;
 | 
			
		||||
    title: string;
 | 
			
		||||
    importMethod: ImportMethod;
 | 
			
		||||
    setImportMethod: (method: ImportMethod) => void;
 | 
			
		||||
    importMethod: 'query' | 'ddl';
 | 
			
		||||
    setImportMethod: (method: 'query' | 'ddl') => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
@@ -97,7 +132,6 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
    const { effectiveTheme } = useTheme();
 | 
			
		||||
    const [errorMessage, setErrorMessage] = useState('');
 | 
			
		||||
    const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
 | 
			
		||||
    const decorationsCollection = useRef<editor.IEditorDecorationsCollection>();
 | 
			
		||||
    const pasteDisposableRef = useRef<IDisposable | null>(null);
 | 
			
		||||
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
@@ -112,20 +146,15 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
    const [isAutoFixing, setIsAutoFixing] = useState(false);
 | 
			
		||||
    const [showAutoFixButton, setShowAutoFixButton] = useState(false);
 | 
			
		||||
 | 
			
		||||
    const clearDecorations = useCallback(() => {
 | 
			
		||||
        clearErrorHighlight(decorationsCollection.current);
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        setScriptResult('');
 | 
			
		||||
        setErrorMessage('');
 | 
			
		||||
        setShowCheckJsonButton(false);
 | 
			
		||||
    }, [importMethod, setScriptResult]);
 | 
			
		||||
 | 
			
		||||
    // Check if the ddl or dbml is valid
 | 
			
		||||
    // Check if the ddl is valid
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        clearDecorations();
 | 
			
		||||
        if (importMethod === 'query') {
 | 
			
		||||
        if (importMethod !== 'ddl') {
 | 
			
		||||
            setSqlValidation(null);
 | 
			
		||||
            setShowAutoFixButton(false);
 | 
			
		||||
            return;
 | 
			
		||||
@@ -134,54 +163,9 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
        if (!scriptResult.trim()) {
 | 
			
		||||
            setSqlValidation(null);
 | 
			
		||||
            setShowAutoFixButton(false);
 | 
			
		||||
            setErrorMessage('');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (importMethod === 'dbml') {
 | 
			
		||||
            // Validate DBML by parsing it
 | 
			
		||||
            const validateResponse = verifyDBML(scriptResult, { databaseType });
 | 
			
		||||
            if (!validateResponse.hasError) {
 | 
			
		||||
                setErrorMessage('');
 | 
			
		||||
                setSqlValidation({
 | 
			
		||||
                    isValid: true,
 | 
			
		||||
                    errors: [],
 | 
			
		||||
                    warnings: [],
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                let errorMsg = 'Invalid DBML syntax';
 | 
			
		||||
                let line: number = 1;
 | 
			
		||||
 | 
			
		||||
                if (validateResponse.parsedError) {
 | 
			
		||||
                    errorMsg = validateResponse.parsedError.message;
 | 
			
		||||
                    line = validateResponse.parsedError.line;
 | 
			
		||||
                    highlightErrorLine({
 | 
			
		||||
                        error: validateResponse.parsedError,
 | 
			
		||||
                        model: editorRef.current?.getModel(),
 | 
			
		||||
                        editorDecorationsCollection:
 | 
			
		||||
                            decorationsCollection.current,
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                setSqlValidation({
 | 
			
		||||
                    isValid: false,
 | 
			
		||||
                    errors: [
 | 
			
		||||
                        {
 | 
			
		||||
                            message: errorMsg,
 | 
			
		||||
                            line: line,
 | 
			
		||||
                            type: 'syntax' as const,
 | 
			
		||||
                        },
 | 
			
		||||
                    ],
 | 
			
		||||
                    warnings: [],
 | 
			
		||||
                });
 | 
			
		||||
                setErrorMessage(errorMsg);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setShowAutoFixButton(false);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // SQL validation
 | 
			
		||||
        // First run our validation based on database type
 | 
			
		||||
        const validation = validateSQL(scriptResult, databaseType);
 | 
			
		||||
        setSqlValidation(validation);
 | 
			
		||||
@@ -208,7 +192,7 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
                setErrorMessage(result.error);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }, [importMethod, scriptResult, databaseType, clearDecorations]);
 | 
			
		||||
    }, [importMethod, scriptResult, databaseType]);
 | 
			
		||||
 | 
			
		||||
    // Check if the script result is a valid JSON
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
@@ -336,8 +320,6 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
    const handleEditorDidMount = useCallback(
 | 
			
		||||
        (editor: editor.IStandaloneCodeEditor) => {
 | 
			
		||||
            editorRef.current = editor;
 | 
			
		||||
            decorationsCollection.current =
 | 
			
		||||
                editor.createDecorationsCollection();
 | 
			
		||||
 | 
			
		||||
            // Cleanup previous disposable if it exists
 | 
			
		||||
            if (pasteDisposableRef.current) {
 | 
			
		||||
@@ -356,7 +338,7 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
                const isLargeFile = calculateIsLargeFile(content);
 | 
			
		||||
 | 
			
		||||
                // First, detect content type to determine if we should switch modes
 | 
			
		||||
                const detectedType = detectImportMethod(content);
 | 
			
		||||
                const detectedType = detectContentType(content);
 | 
			
		||||
                if (detectedType && detectedType !== importMethod) {
 | 
			
		||||
                    // Switch to the detected mode immediately
 | 
			
		||||
                    setImportMethod(detectedType);
 | 
			
		||||
@@ -370,7 +352,7 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
                                ?.run();
 | 
			
		||||
                        }, 100);
 | 
			
		||||
                    }
 | 
			
		||||
                    // For DDL and DBML modes, do NOT format as it can break the syntax
 | 
			
		||||
                    // For DDL mode, do NOT format as it can break the SQL
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Content type didn't change, apply formatting based on current mode
 | 
			
		||||
                    if (importMethod === 'query' && !isLargeFile) {
 | 
			
		||||
@@ -381,7 +363,7 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
                                ?.run();
 | 
			
		||||
                        }, 100);
 | 
			
		||||
                    }
 | 
			
		||||
                    // For DDL and DBML modes or large files, do NOT format
 | 
			
		||||
                    // For DDL mode or large files, do NOT format
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -428,25 +410,16 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
                <div className="w-full text-center text-xs text-muted-foreground">
 | 
			
		||||
                    {importMethod === 'query'
 | 
			
		||||
                        ? 'Smart Query Output'
 | 
			
		||||
                        : importMethod === 'dbml'
 | 
			
		||||
                          ? 'DBML Script'
 | 
			
		||||
                          : 'SQL Script'}
 | 
			
		||||
                        : 'SQL Script'}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div className="flex-1 overflow-hidden">
 | 
			
		||||
                    <Suspense fallback={<Spinner />}>
 | 
			
		||||
                        <Editor
 | 
			
		||||
                            value={scriptResult}
 | 
			
		||||
                            onChange={debouncedHandleInputChange}
 | 
			
		||||
                            language={
 | 
			
		||||
                                importMethod === 'query'
 | 
			
		||||
                                    ? 'json'
 | 
			
		||||
                                    : importMethod === 'dbml'
 | 
			
		||||
                                      ? 'dbml'
 | 
			
		||||
                                      : 'sql'
 | 
			
		||||
                            }
 | 
			
		||||
                            language={importMethod === 'query' ? 'json' : 'sql'}
 | 
			
		||||
                            loading={<Spinner />}
 | 
			
		||||
                            onMount={handleEditorDidMount}
 | 
			
		||||
                            beforeMount={setupDBMLLanguage}
 | 
			
		||||
                            theme={
 | 
			
		||||
                                effectiveTheme === 'dark'
 | 
			
		||||
                                    ? 'dbml-dark'
 | 
			
		||||
@@ -457,6 +430,7 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
                                minimap: { enabled: false },
 | 
			
		||||
                                scrollBeyondLastLine: false,
 | 
			
		||||
                                automaticLayout: true,
 | 
			
		||||
                                glyphMargin: false,
 | 
			
		||||
                                lineNumbers: 'on',
 | 
			
		||||
                                guides: {
 | 
			
		||||
                                    indentation: false,
 | 
			
		||||
@@ -481,9 +455,7 @@ export const ImportDatabase: React.FC<ImportDatabaseProps> = ({
 | 
			
		||||
                    </Suspense>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                {errorMessage ||
 | 
			
		||||
                ((importMethod === 'ddl' || importMethod === 'dbml') &&
 | 
			
		||||
                    sqlValidation) ? (
 | 
			
		||||
                {errorMessage || (importMethod === 'ddl' && sqlValidation) ? (
 | 
			
		||||
                    <SQLValidationStatus
 | 
			
		||||
                        validation={sqlValidation}
 | 
			
		||||
                        errorMessage={errorMessage}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,11 +15,9 @@ import {
 | 
			
		||||
    AvatarImage,
 | 
			
		||||
} from '@/components/avatar/avatar';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { Code, FileCode } from 'lucide-react';
 | 
			
		||||
import { Code } from 'lucide-react';
 | 
			
		||||
import { SmartQueryInstructions } from './instructions/smart-query-instructions';
 | 
			
		||||
import { DDLInstructions } from './instructions/ddl-instructions';
 | 
			
		||||
import { DBMLInstructions } from './instructions/dbml-instructions';
 | 
			
		||||
import type { ImportMethod } from '@/lib/import-method/import-method';
 | 
			
		||||
 | 
			
		||||
const DatabasesWithoutDDLInstructions: DatabaseType[] = [
 | 
			
		||||
    DatabaseType.CLICKHOUSE,
 | 
			
		||||
@@ -32,8 +30,8 @@ export interface InstructionsSectionProps {
 | 
			
		||||
    setDatabaseEdition: React.Dispatch<
 | 
			
		||||
        React.SetStateAction<DatabaseEdition | undefined>
 | 
			
		||||
    >;
 | 
			
		||||
    importMethod: ImportMethod;
 | 
			
		||||
    setImportMethod: (method: ImportMethod) => void;
 | 
			
		||||
    importMethod: 'query' | 'ddl';
 | 
			
		||||
    setImportMethod: (method: 'query' | 'ddl') => void;
 | 
			
		||||
    showSSMSInfoDialog: boolean;
 | 
			
		||||
    setShowSSMSInfoDialog: (show: boolean) => void;
 | 
			
		||||
}
 | 
			
		||||
@@ -117,60 +115,48 @@ export const InstructionsSection: React.FC<InstructionsSectionProps> = ({
 | 
			
		||||
                </div>
 | 
			
		||||
            ) : null}
 | 
			
		||||
 | 
			
		||||
            <div className="flex flex-col gap-1">
 | 
			
		||||
                <p className="text-sm leading-6 text-primary">
 | 
			
		||||
                    How would you like to import?
 | 
			
		||||
                </p>
 | 
			
		||||
                <ToggleGroup
 | 
			
		||||
                    type="single"
 | 
			
		||||
                    className="ml-1 flex-wrap justify-start gap-2"
 | 
			
		||||
                    value={importMethod}
 | 
			
		||||
                    onValueChange={(value) => {
 | 
			
		||||
                        let selectedImportMethod: ImportMethod = 'query';
 | 
			
		||||
                        if (value) {
 | 
			
		||||
                            selectedImportMethod = value as ImportMethod;
 | 
			
		||||
                        }
 | 
			
		||||
            {DatabasesWithoutDDLInstructions.includes(databaseType) ? null : (
 | 
			
		||||
                <div className="flex flex-col gap-1">
 | 
			
		||||
                    <p className="text-sm leading-6 text-primary">
 | 
			
		||||
                        How would you like to import?
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <ToggleGroup
 | 
			
		||||
                        type="single"
 | 
			
		||||
                        className="ml-1 flex-wrap justify-start gap-2"
 | 
			
		||||
                        value={importMethod}
 | 
			
		||||
                        onValueChange={(value) => {
 | 
			
		||||
                            let selectedImportMethod: 'query' | 'ddl' = 'query';
 | 
			
		||||
                            if (value) {
 | 
			
		||||
                                selectedImportMethod = value as 'query' | 'ddl';
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                        setImportMethod(selectedImportMethod);
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    <ToggleGroupItem
 | 
			
		||||
                        value="query"
 | 
			
		||||
                        variant="outline"
 | 
			
		||||
                        className="h-6 gap-1 p-0 px-2 shadow-none data-[state=on]:bg-slate-200 dark:data-[state=on]:bg-slate-700"
 | 
			
		||||
                            setImportMethod(selectedImportMethod);
 | 
			
		||||
                        }}
 | 
			
		||||
                    >
 | 
			
		||||
                        <Avatar className="h-3 w-4 rounded-none">
 | 
			
		||||
                            <AvatarImage src={logo} alt="query" />
 | 
			
		||||
                            <AvatarFallback>Query</AvatarFallback>
 | 
			
		||||
                        </Avatar>
 | 
			
		||||
                        Smart Query
 | 
			
		||||
                    </ToggleGroupItem>
 | 
			
		||||
                    {!DatabasesWithoutDDLInstructions.includes(
 | 
			
		||||
                        databaseType
 | 
			
		||||
                    ) && (
 | 
			
		||||
                        <ToggleGroupItem
 | 
			
		||||
                            value="query"
 | 
			
		||||
                            variant="outline"
 | 
			
		||||
                            className="h-6 gap-1 p-0 px-2 shadow-none data-[state=on]:bg-slate-200 dark:data-[state=on]:bg-slate-700"
 | 
			
		||||
                        >
 | 
			
		||||
                            <Avatar className="h-3 w-4 rounded-none">
 | 
			
		||||
                                <AvatarImage src={logo} alt="query" />
 | 
			
		||||
                                <AvatarFallback>Query</AvatarFallback>
 | 
			
		||||
                            </Avatar>
 | 
			
		||||
                            Smart Query
 | 
			
		||||
                        </ToggleGroupItem>
 | 
			
		||||
                        <ToggleGroupItem
 | 
			
		||||
                            value="ddl"
 | 
			
		||||
                            variant="outline"
 | 
			
		||||
                            className="h-6 gap-1 p-0 px-2 shadow-none data-[state=on]:bg-slate-200 dark:data-[state=on]:bg-slate-700"
 | 
			
		||||
                        >
 | 
			
		||||
                            <Avatar className="size-4 rounded-none">
 | 
			
		||||
                                <FileCode size={16} />
 | 
			
		||||
                                <Code size={16} />
 | 
			
		||||
                            </Avatar>
 | 
			
		||||
                            SQL Script
 | 
			
		||||
                        </ToggleGroupItem>
 | 
			
		||||
                    )}
 | 
			
		||||
                    <ToggleGroupItem
 | 
			
		||||
                        value="dbml"
 | 
			
		||||
                        variant="outline"
 | 
			
		||||
                        className="h-6 gap-1 p-0 px-2 shadow-none data-[state=on]:bg-slate-200 dark:data-[state=on]:bg-slate-700"
 | 
			
		||||
                    >
 | 
			
		||||
                        <Avatar className="size-4 rounded-none">
 | 
			
		||||
                            <Code size={16} />
 | 
			
		||||
                        </Avatar>
 | 
			
		||||
                        DBML
 | 
			
		||||
                    </ToggleGroupItem>
 | 
			
		||||
                </ToggleGroup>
 | 
			
		||||
            </div>
 | 
			
		||||
                    </ToggleGroup>
 | 
			
		||||
                </div>
 | 
			
		||||
            )}
 | 
			
		||||
 | 
			
		||||
            <div className="flex flex-col gap-2">
 | 
			
		||||
                <div className="text-sm font-semibold">Instructions:</div>
 | 
			
		||||
@@ -181,13 +167,8 @@ export const InstructionsSection: React.FC<InstructionsSectionProps> = ({
 | 
			
		||||
                        showSSMSInfoDialog={showSSMSInfoDialog}
 | 
			
		||||
                        setShowSSMSInfoDialog={setShowSSMSInfoDialog}
 | 
			
		||||
                    />
 | 
			
		||||
                ) : importMethod === 'ddl' ? (
 | 
			
		||||
                    <DDLInstructions
 | 
			
		||||
                        databaseType={databaseType}
 | 
			
		||||
                        databaseEdition={databaseEdition}
 | 
			
		||||
                    />
 | 
			
		||||
                ) : (
 | 
			
		||||
                    <DBMLInstructions
 | 
			
		||||
                    <DDLInstructions
 | 
			
		||||
                        databaseType={databaseType}
 | 
			
		||||
                        databaseEdition={databaseEdition}
 | 
			
		||||
                    />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,47 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import type { DatabaseType } from '@/lib/domain/database-type';
 | 
			
		||||
import type { DatabaseEdition } from '@/lib/domain/database-edition';
 | 
			
		||||
import { CodeSnippet } from '@/components/code-snippet/code-snippet';
 | 
			
		||||
import { setupDBMLLanguage } from '@/components/code-snippet/languages/dbml-language';
 | 
			
		||||
 | 
			
		||||
export interface DBMLInstructionsProps {
 | 
			
		||||
    databaseType: DatabaseType;
 | 
			
		||||
    databaseEdition?: DatabaseEdition;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const DBMLInstructions: React.FC<DBMLInstructionsProps> = () => {
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
            <div className="flex flex-col gap-1 text-sm text-primary">
 | 
			
		||||
                <div>
 | 
			
		||||
                    Paste your DBML (Database Markup Language) schema definition
 | 
			
		||||
                    here →
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div className="flex h-64 flex-col gap-1 text-sm text-primary">
 | 
			
		||||
                <h4 className="text-xs font-medium">Example:</h4>
 | 
			
		||||
                <CodeSnippet
 | 
			
		||||
                    className="h-full"
 | 
			
		||||
                    allowCopy={false}
 | 
			
		||||
                    editorProps={{
 | 
			
		||||
                        beforeMount: setupDBMLLanguage,
 | 
			
		||||
                    }}
 | 
			
		||||
                    code={`Table users {
 | 
			
		||||
  id int [pk]
 | 
			
		||||
  username varchar
 | 
			
		||||
  email varchar
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Table posts {
 | 
			
		||||
  id int [pk]
 | 
			
		||||
  user_id int [ref: > users.id]
 | 
			
		||||
  title varchar
 | 
			
		||||
  content text
 | 
			
		||||
}`}
 | 
			
		||||
                    language={'dbml'}
 | 
			
		||||
                />
 | 
			
		||||
            </div>
 | 
			
		||||
        </>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@@ -43,8 +43,8 @@ const DDLInstructionsMap: Record<DatabaseType, DDLInstruction[]> = {
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            text: 'Execute the following command in your terminal:',
 | 
			
		||||
            code: `sqlite3 <database_file_path>\n".schema" > <output_file_path>`,
 | 
			
		||||
            example: `sqlite3 my_db.db\n".schema" > schema_export.sql`,
 | 
			
		||||
            code: `sqlite3 <database_file_path>\n.dump > <output_file_path>`,
 | 
			
		||||
            example: `sqlite3 my_db.db\n.dump > schema_export.sql`,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            text: 'Open the exported SQL file, copy its contents, and paste them here.',
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,7 @@ export const SQLValidationStatus: React.FC<SQLValidationStatusProps> = ({
 | 
			
		||||
 | 
			
		||||
            {hasErrors ? (
 | 
			
		||||
                <div className="rounded-md border border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950">
 | 
			
		||||
                    <ScrollArea className="h-fit max-h-24">
 | 
			
		||||
                    <ScrollArea className="h-24">
 | 
			
		||||
                        <div className="space-y-3 p-3 pt-2 text-red-700 dark:text-red-300">
 | 
			
		||||
                            {validation?.errors
 | 
			
		||||
                                .slice(0, 3)
 | 
			
		||||
@@ -137,7 +137,7 @@ export const SQLValidationStatus: React.FC<SQLValidationStatusProps> = ({
 | 
			
		||||
 | 
			
		||||
            {hasWarnings && !hasErrors ? (
 | 
			
		||||
                <div className="rounded-md border border-sky-200 bg-sky-50 dark:border-sky-800 dark:bg-sky-950">
 | 
			
		||||
                    <ScrollArea className="h-fit max-h-24">
 | 
			
		||||
                    <ScrollArea className="h-24">
 | 
			
		||||
                        <div className="space-y-3 p-3 pt-2 text-sky-700 dark:text-sky-300">
 | 
			
		||||
                            <div className="flex items-start gap-2">
 | 
			
		||||
                                <AlertTriangle className="mt-0.5 size-4 shrink-0 text-sky-700 dark:text-sky-300" />
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,6 @@ export const SelectTables: React.FC<SelectTablesProps> = ({
 | 
			
		||||
    const [showTables, setShowTables] = useState(true);
 | 
			
		||||
    const [showViews, setShowViews] = useState(false);
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
    const [isImporting, setIsImporting] = useState(false);
 | 
			
		||||
 | 
			
		||||
    // Prepare all tables and views with their metadata
 | 
			
		||||
    const allTables = useMemo(() => {
 | 
			
		||||
@@ -259,37 +258,22 @@ export const SelectTables: React.FC<SelectTablesProps> = ({
 | 
			
		||||
        setSelectedTables(new Set());
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    const handleConfirm = useCallback(async () => {
 | 
			
		||||
        if (isImporting) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    const handleConfirm = useCallback(() => {
 | 
			
		||||
        const selectedTableObjects: SelectedTable[] = Array.from(selectedTables)
 | 
			
		||||
            .map((key): SelectedTable | null => {
 | 
			
		||||
                const table = allTables.find((t) => t.key === key);
 | 
			
		||||
                if (!table) return null;
 | 
			
		||||
 | 
			
		||||
        setIsImporting(true);
 | 
			
		||||
                return {
 | 
			
		||||
                    schema: table.schema,
 | 
			
		||||
                    table: table.tableName,
 | 
			
		||||
                    type: table.type,
 | 
			
		||||
                } satisfies SelectedTable;
 | 
			
		||||
            })
 | 
			
		||||
            .filter((t): t is SelectedTable => t !== null);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const selectedTableObjects: SelectedTable[] = Array.from(
 | 
			
		||||
                selectedTables
 | 
			
		||||
            )
 | 
			
		||||
                .map((key): SelectedTable | null => {
 | 
			
		||||
                    const table = allTables.find((t) => t.key === key);
 | 
			
		||||
                    if (!table) return null;
 | 
			
		||||
 | 
			
		||||
                    return {
 | 
			
		||||
                        schema: table.schema,
 | 
			
		||||
                        table: table.tableName,
 | 
			
		||||
                        type: table.type,
 | 
			
		||||
                    } satisfies SelectedTable;
 | 
			
		||||
                })
 | 
			
		||||
                .filter((t): t is SelectedTable => t !== null);
 | 
			
		||||
 | 
			
		||||
            await onImport({
 | 
			
		||||
                selectedTables: selectedTableObjects,
 | 
			
		||||
                databaseMetadata,
 | 
			
		||||
            });
 | 
			
		||||
        } finally {
 | 
			
		||||
            setIsImporting(false);
 | 
			
		||||
        }
 | 
			
		||||
    }, [selectedTables, allTables, onImport, databaseMetadata, isImporting]);
 | 
			
		||||
        onImport({ selectedTables: selectedTableObjects, databaseMetadata });
 | 
			
		||||
    }, [selectedTables, allTables, onImport, databaseMetadata]);
 | 
			
		||||
 | 
			
		||||
    const { isMd: isDesktop } = useBreakpoint('md');
 | 
			
		||||
 | 
			
		||||
@@ -651,29 +635,27 @@ export const SelectTables: React.FC<SelectTablesProps> = ({
 | 
			
		||||
                </div>
 | 
			
		||||
                {isDesktop ? renderPagination() : null}
 | 
			
		||||
            </DialogInternalContent>
 | 
			
		||||
            <DialogFooter className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:space-x-2 md:justify-between md:gap-0">
 | 
			
		||||
                <Button
 | 
			
		||||
                    type="button"
 | 
			
		||||
                    variant="secondary"
 | 
			
		||||
                    onClick={onBack}
 | 
			
		||||
                    disabled={isImporting}
 | 
			
		||||
                >
 | 
			
		||||
            <DialogFooter
 | 
			
		||||
                // className={cn(
 | 
			
		||||
                //     'gap-2',
 | 
			
		||||
                //     isDesktop
 | 
			
		||||
                //         ? 'flex items-center justify-between'
 | 
			
		||||
                //         : 'flex flex-col'
 | 
			
		||||
                // )}
 | 
			
		||||
                className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:space-x-2 md:justify-between md:gap-0"
 | 
			
		||||
            >
 | 
			
		||||
                {/* Desktop layout */}
 | 
			
		||||
 | 
			
		||||
                <Button type="button" variant="secondary" onClick={onBack}>
 | 
			
		||||
                    {t('new_diagram_dialog.back')}
 | 
			
		||||
                </Button>
 | 
			
		||||
 | 
			
		||||
                <Button
 | 
			
		||||
                    onClick={handleConfirm}
 | 
			
		||||
                    disabled={selectedTables.size === 0 || isImporting}
 | 
			
		||||
                    disabled={selectedTables.size === 0}
 | 
			
		||||
                    className="bg-pink-500 text-white hover:bg-pink-600"
 | 
			
		||||
                >
 | 
			
		||||
                    {isImporting ? (
 | 
			
		||||
                        <>
 | 
			
		||||
                            <Spinner className="mr-2 size-4 text-white" />
 | 
			
		||||
                            Importing...
 | 
			
		||||
                        </>
 | 
			
		||||
                    ) : (
 | 
			
		||||
                        `Import ${selectedTables.size} Tables`
 | 
			
		||||
                    )}
 | 
			
		||||
                    Import {selectedTables.size} Tables
 | 
			
		||||
                </Button>
 | 
			
		||||
 | 
			
		||||
                {!isDesktop ? renderPagination() : null}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ import { Dialog, DialogContent } from '@/components/dialog/dialog';
 | 
			
		||||
import { DatabaseType } from '@/lib/domain/database-type';
 | 
			
		||||
import { useStorage } from '@/hooks/use-storage';
 | 
			
		||||
import type { Diagram } from '@/lib/domain/diagram';
 | 
			
		||||
import { loadFromDatabaseMetadata } from '@/lib/data/import-metadata/import';
 | 
			
		||||
import { loadFromDatabaseMetadata } from '@/lib/domain/diagram';
 | 
			
		||||
import { useNavigate } from 'react-router-dom';
 | 
			
		||||
import { useConfig } from '@/hooks/use-config';
 | 
			
		||||
import type { DatabaseMetadata } from '@/lib/data/import-metadata/metadata-types/database-metadata';
 | 
			
		||||
@@ -22,11 +22,6 @@ import { sqlImportToDiagram } from '@/lib/data/sql-import';
 | 
			
		||||
import type { SelectedTable } from '@/lib/data/import-metadata/filter-metadata';
 | 
			
		||||
import { filterMetadataByTables } from '@/lib/data/import-metadata/filter-metadata';
 | 
			
		||||
import { MAX_TABLES_WITHOUT_SHOWING_FILTER } from '../common/select-tables/constants';
 | 
			
		||||
import {
 | 
			
		||||
    defaultDBMLDiagramName,
 | 
			
		||||
    importDBMLToDiagram,
 | 
			
		||||
} from '@/lib/dbml/dbml-import/dbml-import';
 | 
			
		||||
import type { ImportMethod } from '@/lib/import-method/import-method';
 | 
			
		||||
 | 
			
		||||
export interface CreateDiagramDialogProps extends BaseDialogProps {}
 | 
			
		||||
 | 
			
		||||
@@ -35,11 +30,11 @@ export const CreateDiagramDialog: React.FC<CreateDiagramDialogProps> = ({
 | 
			
		||||
}) => {
 | 
			
		||||
    const { diagramId } = useChartDB();
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
    const [importMethod, setImportMethod] = useState<ImportMethod>('query');
 | 
			
		||||
    const [importMethod, setImportMethod] = useState<'query' | 'ddl'>('query');
 | 
			
		||||
    const [databaseType, setDatabaseType] = useState<DatabaseType>(
 | 
			
		||||
        DatabaseType.GENERIC
 | 
			
		||||
    );
 | 
			
		||||
    const { closeCreateDiagramDialog } = useDialog();
 | 
			
		||||
    const { closeCreateDiagramDialog, openImportDBMLDialog } = useDialog();
 | 
			
		||||
    const { updateConfig } = useConfig();
 | 
			
		||||
    const [scriptResult, setScriptResult] = useState('');
 | 
			
		||||
    const [databaseEdition, setDatabaseEdition] = useState<
 | 
			
		||||
@@ -94,14 +89,6 @@ export const CreateDiagramDialog: React.FC<CreateDiagramDialogProps> = ({
 | 
			
		||||
                    sourceDatabaseType: databaseType,
 | 
			
		||||
                    targetDatabaseType: databaseType,
 | 
			
		||||
                });
 | 
			
		||||
            } else if (importMethod === 'dbml') {
 | 
			
		||||
                diagram = await importDBMLToDiagram(scriptResult, {
 | 
			
		||||
                    databaseType,
 | 
			
		||||
                });
 | 
			
		||||
                // Update the diagram name if it's the default
 | 
			
		||||
                if (diagram.name === defaultDBMLDiagramName) {
 | 
			
		||||
                    diagram.name = `Diagram ${diagramNumber}`;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                let metadata: DatabaseMetadata | undefined = databaseMetadata;
 | 
			
		||||
 | 
			
		||||
@@ -165,6 +152,10 @@ export const CreateDiagramDialog: React.FC<CreateDiagramDialogProps> = ({
 | 
			
		||||
        await updateConfig({ config: { defaultDiagramId: diagram.id } });
 | 
			
		||||
        closeCreateDiagramDialog();
 | 
			
		||||
        navigate(`/diagrams/${diagram.id}`);
 | 
			
		||||
        setTimeout(
 | 
			
		||||
            () => openImportDBMLDialog({ withCreateEmptyDiagram: true }),
 | 
			
		||||
            700
 | 
			
		||||
        );
 | 
			
		||||
    }, [
 | 
			
		||||
        databaseType,
 | 
			
		||||
        addDiagram,
 | 
			
		||||
@@ -173,13 +164,14 @@ export const CreateDiagramDialog: React.FC<CreateDiagramDialogProps> = ({
 | 
			
		||||
        navigate,
 | 
			
		||||
        updateConfig,
 | 
			
		||||
        diagramNumber,
 | 
			
		||||
        openImportDBMLDialog,
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    const importNewDiagramOrFilterTables = useCallback(async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            setIsParsingMetadata(true);
 | 
			
		||||
 | 
			
		||||
            if (importMethod === 'ddl' || importMethod === 'dbml') {
 | 
			
		||||
            if (importMethod === 'ddl') {
 | 
			
		||||
                await importNewDiagram();
 | 
			
		||||
            } else {
 | 
			
		||||
                // Parse metadata asynchronously to avoid blocking the UI
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +1,20 @@
 | 
			
		||||
import React, { useCallback, useMemo, useState } from 'react';
 | 
			
		||||
import React, { useMemo, useState } from 'react';
 | 
			
		||||
import { ToggleGroup } from '@/components/toggle/toggle-group';
 | 
			
		||||
import { DatabaseType } from '@/lib/domain/database-type';
 | 
			
		||||
import { DatabaseOption } from './database-option';
 | 
			
		||||
import { ExampleOption } from './example-option';
 | 
			
		||||
import { Button } from '@/components/button/button';
 | 
			
		||||
import { ChevronDown, ChevronUp } from 'lucide-react';
 | 
			
		||||
import {
 | 
			
		||||
    Tabs,
 | 
			
		||||
    TabsContent,
 | 
			
		||||
    TabsList,
 | 
			
		||||
    TabsTrigger,
 | 
			
		||||
} from '@/components/tabs/tabs';
 | 
			
		||||
export interface SelectDatabaseContentProps {
 | 
			
		||||
    databaseType: DatabaseType;
 | 
			
		||||
    setDatabaseType: React.Dispatch<React.SetStateAction<DatabaseType>>;
 | 
			
		||||
    onContinue: (selectedDatabaseType: DatabaseType) => void;
 | 
			
		||||
    onContinue: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ROW_SIZE = 3;
 | 
			
		||||
const ROWS = 2;
 | 
			
		||||
const TOTAL_SLOTS = ROW_SIZE * ROWS;
 | 
			
		||||
 | 
			
		||||
// Transactional databases - OLTP systems optimized for frequent read/write operations
 | 
			
		||||
const TRANSACTIONAL_DB_TYPES: DatabaseType[] = [
 | 
			
		||||
const SUPPORTED_DB_TYPES: DatabaseType[] = [
 | 
			
		||||
    DatabaseType.MYSQL,
 | 
			
		||||
    DatabaseType.POSTGRESQL,
 | 
			
		||||
    DatabaseType.MARIADB,
 | 
			
		||||
@@ -30,87 +22,69 @@ const TRANSACTIONAL_DB_TYPES: DatabaseType[] = [
 | 
			
		||||
    DatabaseType.SQL_SERVER,
 | 
			
		||||
    DatabaseType.ORACLE,
 | 
			
		||||
    DatabaseType.COCKROACHDB,
 | 
			
		||||
    DatabaseType.CLICKHOUSE,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// Analytical databases - OLAP systems optimized for complex queries and analytics
 | 
			
		||||
const ANALYTICAL_DB_TYPES: DatabaseType[] = [DatabaseType.CLICKHOUSE];
 | 
			
		||||
 | 
			
		||||
export const SelectDatabaseContent: React.FC<SelectDatabaseContentProps> = ({
 | 
			
		||||
    databaseType,
 | 
			
		||||
    setDatabaseType,
 | 
			
		||||
    onContinue,
 | 
			
		||||
}) => {
 | 
			
		||||
    const [activeTab, setActiveTab] = useState<'transactional' | 'analytical'>(
 | 
			
		||||
        'transactional'
 | 
			
		||||
    );
 | 
			
		||||
    const [currentRow, setCurrentRow] = useState(0);
 | 
			
		||||
 | 
			
		||||
    const currentDbTypes =
 | 
			
		||||
        activeTab === 'transactional'
 | 
			
		||||
            ? TRANSACTIONAL_DB_TYPES
 | 
			
		||||
            : ANALYTICAL_DB_TYPES;
 | 
			
		||||
 | 
			
		||||
    const currentDatabasesTypes = useMemo(
 | 
			
		||||
        () =>
 | 
			
		||||
            currentDbTypes.slice(
 | 
			
		||||
            SUPPORTED_DB_TYPES.slice(
 | 
			
		||||
                currentRow * ROW_SIZE,
 | 
			
		||||
                currentRow * ROW_SIZE + TOTAL_SLOTS
 | 
			
		||||
            ),
 | 
			
		||||
        [currentRow, currentDbTypes]
 | 
			
		||||
        [currentRow]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const hasNextRow = useMemo(
 | 
			
		||||
        () => (currentRow + 1) * ROW_SIZE < currentDbTypes.length,
 | 
			
		||||
        [currentRow, currentDbTypes]
 | 
			
		||||
        () => (currentRow + 1) * ROW_SIZE < SUPPORTED_DB_TYPES.length,
 | 
			
		||||
        [currentRow]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const hasPreviousRow = useMemo(() => currentRow > 0, [currentRow]);
 | 
			
		||||
 | 
			
		||||
    const toggleRow = useCallback(() => {
 | 
			
		||||
    const toggleRow = () => {
 | 
			
		||||
        if (currentRow === 0 && hasNextRow) {
 | 
			
		||||
            setCurrentRow(currentRow + 1);
 | 
			
		||||
        } else if (currentRow > 0) {
 | 
			
		||||
            setCurrentRow(currentRow - 1);
 | 
			
		||||
        }
 | 
			
		||||
    }, [currentRow, hasNextRow]);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const handleTabChange = useCallback((value: string) => {
 | 
			
		||||
        setActiveTab(value as 'transactional' | 'analytical');
 | 
			
		||||
        setCurrentRow(0); // Reset to first row when switching tabs
 | 
			
		||||
    }, []);
 | 
			
		||||
    return (
 | 
			
		||||
        <div className="flex flex-1 flex-col items-center justify-center gap-4">
 | 
			
		||||
            <ToggleGroup
 | 
			
		||||
                value={databaseType}
 | 
			
		||||
                onValueChange={(value: DatabaseType) => {
 | 
			
		||||
                    if (!value) {
 | 
			
		||||
                        setDatabaseType(DatabaseType.GENERIC);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        setDatabaseType(value);
 | 
			
		||||
                        onContinue();
 | 
			
		||||
                    }
 | 
			
		||||
                }}
 | 
			
		||||
                type="single"
 | 
			
		||||
                className="grid grid-flow-row grid-cols-3 gap-6"
 | 
			
		||||
            >
 | 
			
		||||
                {Array.from({ length: TOTAL_SLOTS }).map((_, index) =>
 | 
			
		||||
                    currentDatabasesTypes?.[index] ? (
 | 
			
		||||
                        <DatabaseOption
 | 
			
		||||
                            key={currentDatabasesTypes[index]}
 | 
			
		||||
                            type={currentDatabasesTypes[index]}
 | 
			
		||||
                        />
 | 
			
		||||
                    ) : null
 | 
			
		||||
                )}
 | 
			
		||||
 | 
			
		||||
    const renderDatabaseGrid = useCallback(
 | 
			
		||||
        () => (
 | 
			
		||||
            <div className="flex min-h-[280px] flex-col md:min-h-[370px]">
 | 
			
		||||
                <ToggleGroup
 | 
			
		||||
                    value={databaseType}
 | 
			
		||||
                    onValueChange={(value: DatabaseType) => {
 | 
			
		||||
                        if (!value) {
 | 
			
		||||
                            setDatabaseType(DatabaseType.GENERIC);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            setDatabaseType(value);
 | 
			
		||||
                            onContinue(value);
 | 
			
		||||
                        }
 | 
			
		||||
                    }}
 | 
			
		||||
                    type="single"
 | 
			
		||||
                    className="grid grid-flow-row grid-cols-3 content-start gap-4"
 | 
			
		||||
                >
 | 
			
		||||
                    {Array.from({ length: TOTAL_SLOTS }).map((_, index) =>
 | 
			
		||||
                        currentDatabasesTypes?.[index] ? (
 | 
			
		||||
                            <DatabaseOption
 | 
			
		||||
                                key={currentDatabasesTypes[index]}
 | 
			
		||||
                                type={currentDatabasesTypes[index]}
 | 
			
		||||
                            />
 | 
			
		||||
                        ) : null
 | 
			
		||||
                    )}
 | 
			
		||||
                </ToggleGroup>
 | 
			
		||||
 | 
			
		||||
                <div className="mt-auto flex flex-col gap-1 pt-4">
 | 
			
		||||
                <div className="col-span-3 flex flex-1 flex-col gap-1">
 | 
			
		||||
                    {hasNextRow || hasPreviousRow ? (
 | 
			
		||||
                        <Button
 | 
			
		||||
                            variant="ghost"
 | 
			
		||||
                            onClick={toggleRow}
 | 
			
		||||
                            className="h-8"
 | 
			
		||||
                            className="col-span-3 h-8"
 | 
			
		||||
                        >
 | 
			
		||||
                            {currentRow === 0 ? (
 | 
			
		||||
                                <div className="flex h-8 w-full cursor-pointer flex-row items-center justify-center gap-2 py-3 text-center md:h-12">
 | 
			
		||||
@@ -131,55 +105,7 @@ export const SelectDatabaseContent: React.FC<SelectDatabaseContentProps> = ({
 | 
			
		||||
                    ) : null}
 | 
			
		||||
                    <ExampleOption />
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        ),
 | 
			
		||||
        [
 | 
			
		||||
            databaseType,
 | 
			
		||||
            currentDatabasesTypes,
 | 
			
		||||
            hasNextRow,
 | 
			
		||||
            hasPreviousRow,
 | 
			
		||||
            onContinue,
 | 
			
		||||
            setDatabaseType,
 | 
			
		||||
            toggleRow,
 | 
			
		||||
            currentRow,
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div className="flex flex-1 flex-col items-center gap-2">
 | 
			
		||||
            <Tabs
 | 
			
		||||
                defaultValue="transactional"
 | 
			
		||||
                value={activeTab}
 | 
			
		||||
                onValueChange={handleTabChange}
 | 
			
		||||
                className="w-auto"
 | 
			
		||||
            >
 | 
			
		||||
                <TabsList className="mb-2 grid size-auto grid-cols-2 gap-1 rounded-xl border bg-background p-1">
 | 
			
		||||
                    <TabsTrigger
 | 
			
		||||
                        value="transactional"
 | 
			
		||||
                        className="gap-1.5 rounded-lg px-3 py-1 text-sm font-medium transition-all data-[state=active]:bg-sky-600 data-[state=active]:text-white data-[state=inactive]:text-muted-foreground data-[state=active]:shadow-sm data-[state=inactive]:hover:bg-muted/50 data-[state=inactive]:hover:text-foreground dark:data-[state=active]:bg-sky-500"
 | 
			
		||||
                    >
 | 
			
		||||
                        Transactional
 | 
			
		||||
                    </TabsTrigger>
 | 
			
		||||
                    <TabsTrigger
 | 
			
		||||
                        value="analytical"
 | 
			
		||||
                        className="gap-1.5 rounded-lg px-3 py-1 text-sm font-medium transition-all data-[state=active]:bg-sky-600 data-[state=active]:text-white data-[state=inactive]:text-muted-foreground data-[state=active]:shadow-sm data-[state=inactive]:hover:bg-muted/50 data-[state=inactive]:hover:text-foreground dark:data-[state=active]:bg-sky-500"
 | 
			
		||||
                    >
 | 
			
		||||
                        Analytical
 | 
			
		||||
                    </TabsTrigger>
 | 
			
		||||
                </TabsList>
 | 
			
		||||
                <TabsContent
 | 
			
		||||
                    value="transactional"
 | 
			
		||||
                    className="mt-0 focus-visible:ring-0 focus-visible:ring-offset-0"
 | 
			
		||||
                >
 | 
			
		||||
                    {renderDatabaseGrid()}
 | 
			
		||||
                </TabsContent>
 | 
			
		||||
                <TabsContent
 | 
			
		||||
                    value="analytical"
 | 
			
		||||
                    className="mt-0 focus-visible:ring-0 focus-visible:ring-offset-0"
 | 
			
		||||
                >
 | 
			
		||||
                    {renderDatabaseGrid()}
 | 
			
		||||
                </TabsContent>
 | 
			
		||||
            </Tabs>
 | 
			
		||||
            </ToggleGroup>
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,6 @@ export const SelectDatabase: React.FC<SelectDatabaseProps> = ({
 | 
			
		||||
                        type="button"
 | 
			
		||||
                        variant="outline"
 | 
			
		||||
                        onClick={createNewDiagram}
 | 
			
		||||
                        disabled={databaseType === DatabaseType.GENERIC}
 | 
			
		||||
                    >
 | 
			
		||||
                        {t('new_diagram_dialog.empty_diagram')}
 | 
			
		||||
                    </Button>
 | 
			
		||||
 
 | 
			
		||||
@@ -218,14 +218,8 @@ export const CreateRelationshipDialog: React.FC<
 | 
			
		||||
                    closeCreateRelationshipDialog();
 | 
			
		||||
                }
 | 
			
		||||
            }}
 | 
			
		||||
            modal={false}
 | 
			
		||||
        >
 | 
			
		||||
            <DialogContent
 | 
			
		||||
                className="flex flex-col overflow-y-auto"
 | 
			
		||||
                showClose
 | 
			
		||||
                forceOverlay
 | 
			
		||||
                onInteractOutside={(e) => e.preventDefault()}
 | 
			
		||||
            >
 | 
			
		||||
            <DialogContent className="flex flex-col overflow-y-auto" showClose>
 | 
			
		||||
                <DialogHeader>
 | 
			
		||||
                    <DialogTitle>
 | 
			
		||||
                        {t('create_relationship_dialog.title')}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,21 +17,15 @@ import { useDialog } from '@/hooks/use-dialog';
 | 
			
		||||
import {
 | 
			
		||||
    exportBaseSQL,
 | 
			
		||||
    exportSQL,
 | 
			
		||||
} from '@/lib/data/sql-export/export-sql-script';
 | 
			
		||||
} from '@/lib/data/export-metadata/export-sql-script';
 | 
			
		||||
import { databaseTypeToLabelMap } from '@/lib/databases';
 | 
			
		||||
import { DatabaseType } from '@/lib/domain/database-type';
 | 
			
		||||
import { shouldShowTablesBySchemaFilter } from '@/lib/domain/db-table';
 | 
			
		||||
import { Annoyed, Sparkles } from 'lucide-react';
 | 
			
		||||
import React, { useCallback, useEffect, useRef } from 'react';
 | 
			
		||||
import { Trans, useTranslation } from 'react-i18next';
 | 
			
		||||
import type { BaseDialogProps } from '../common/base-dialog-props';
 | 
			
		||||
import type { Diagram } from '@/lib/domain/diagram';
 | 
			
		||||
import { useDiagramFilter } from '@/context/diagram-filter-context/use-diagram-filter';
 | 
			
		||||
import {
 | 
			
		||||
    filterDependency,
 | 
			
		||||
    filterRelationship,
 | 
			
		||||
    filterTable,
 | 
			
		||||
} from '@/lib/domain/diagram-filter/filter';
 | 
			
		||||
import { defaultSchemas } from '@/lib/data/default-schemas';
 | 
			
		||||
 | 
			
		||||
export interface ExportSQLDialogProps extends BaseDialogProps {
 | 
			
		||||
    targetDatabaseType: DatabaseType;
 | 
			
		||||
@@ -42,8 +36,7 @@ export const ExportSQLDialog: React.FC<ExportSQLDialogProps> = ({
 | 
			
		||||
    targetDatabaseType,
 | 
			
		||||
}) => {
 | 
			
		||||
    const { closeExportSQLDialog } = useDialog();
 | 
			
		||||
    const { currentDiagram } = useChartDB();
 | 
			
		||||
    const { filter } = useDiagramFilter();
 | 
			
		||||
    const { currentDiagram, filteredSchemas } = useChartDB();
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
    const [script, setScript] = React.useState<string>();
 | 
			
		||||
    const [error, setError] = React.useState<boolean>(false);
 | 
			
		||||
@@ -55,16 +48,7 @@ export const ExportSQLDialog: React.FC<ExportSQLDialogProps> = ({
 | 
			
		||||
        const filteredDiagram: Diagram = {
 | 
			
		||||
            ...currentDiagram,
 | 
			
		||||
            tables: currentDiagram.tables?.filter((table) =>
 | 
			
		||||
                filterTable({
 | 
			
		||||
                    table: {
 | 
			
		||||
                        id: table.id,
 | 
			
		||||
                        schema: table.schema,
 | 
			
		||||
                    },
 | 
			
		||||
                    filter,
 | 
			
		||||
                    options: {
 | 
			
		||||
                        defaultSchema: defaultSchemas[targetDatabaseType],
 | 
			
		||||
                    },
 | 
			
		||||
                })
 | 
			
		||||
                shouldShowTablesBySchemaFilter(table, filteredSchemas)
 | 
			
		||||
            ),
 | 
			
		||||
            relationships: currentDiagram.relationships?.filter((rel) => {
 | 
			
		||||
                const sourceTable = currentDiagram.tables?.find(
 | 
			
		||||
@@ -76,20 +60,11 @@ export const ExportSQLDialog: React.FC<ExportSQLDialogProps> = ({
 | 
			
		||||
                return (
 | 
			
		||||
                    sourceTable &&
 | 
			
		||||
                    targetTable &&
 | 
			
		||||
                    filterRelationship({
 | 
			
		||||
                        tableA: {
 | 
			
		||||
                            id: sourceTable.id,
 | 
			
		||||
                            schema: sourceTable.schema,
 | 
			
		||||
                        },
 | 
			
		||||
                        tableB: {
 | 
			
		||||
                            id: targetTable.id,
 | 
			
		||||
                            schema: targetTable.schema,
 | 
			
		||||
                        },
 | 
			
		||||
                        filter,
 | 
			
		||||
                        options: {
 | 
			
		||||
                            defaultSchema: defaultSchemas[targetDatabaseType],
 | 
			
		||||
                        },
 | 
			
		||||
                    })
 | 
			
		||||
                    shouldShowTablesBySchemaFilter(
 | 
			
		||||
                        sourceTable,
 | 
			
		||||
                        filteredSchemas
 | 
			
		||||
                    ) &&
 | 
			
		||||
                    shouldShowTablesBySchemaFilter(targetTable, filteredSchemas)
 | 
			
		||||
                );
 | 
			
		||||
            }),
 | 
			
		||||
            dependencies: currentDiagram.dependencies?.filter((dep) => {
 | 
			
		||||
@@ -102,20 +77,11 @@ export const ExportSQLDialog: React.FC<ExportSQLDialogProps> = ({
 | 
			
		||||
                return (
 | 
			
		||||
                    table &&
 | 
			
		||||
                    dependentTable &&
 | 
			
		||||
                    filterDependency({
 | 
			
		||||
                        tableA: {
 | 
			
		||||
                            id: table.id,
 | 
			
		||||
                            schema: table.schema,
 | 
			
		||||
                        },
 | 
			
		||||
                        tableB: {
 | 
			
		||||
                            id: dependentTable.id,
 | 
			
		||||
                            schema: dependentTable.schema,
 | 
			
		||||
                        },
 | 
			
		||||
                        filter,
 | 
			
		||||
                        options: {
 | 
			
		||||
                            defaultSchema: defaultSchemas[targetDatabaseType],
 | 
			
		||||
                        },
 | 
			
		||||
                    })
 | 
			
		||||
                    shouldShowTablesBySchemaFilter(table, filteredSchemas) &&
 | 
			
		||||
                    shouldShowTablesBySchemaFilter(
 | 
			
		||||
                        dependentTable,
 | 
			
		||||
                        filteredSchemas
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
            }),
 | 
			
		||||
        };
 | 
			
		||||
@@ -135,7 +101,7 @@ export const ExportSQLDialog: React.FC<ExportSQLDialogProps> = ({
 | 
			
		||||
                signal: abortControllerRef.current?.signal,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }, [targetDatabaseType, currentDiagram, filter]);
 | 
			
		||||
    }, [targetDatabaseType, currentDiagram, filteredSchemas]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (!dialog.open) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import type { DatabaseEdition } from '@/lib/domain/database-edition';
 | 
			
		||||
import type { DatabaseMetadata } from '@/lib/data/import-metadata/metadata-types/database-metadata';
 | 
			
		||||
import { loadDatabaseMetadata } from '@/lib/data/import-metadata/metadata-types/database-metadata';
 | 
			
		||||
import type { Diagram } from '@/lib/domain/diagram';
 | 
			
		||||
import { loadFromDatabaseMetadata } from '@/lib/data/import-metadata/import';
 | 
			
		||||
import { loadFromDatabaseMetadata } from '@/lib/domain/diagram';
 | 
			
		||||
import { useChartDB } from '@/hooks/use-chartdb';
 | 
			
		||||
import { useRedoUndoStack } from '@/hooks/use-redo-undo-stack';
 | 
			
		||||
import { Trans, useTranslation } from 'react-i18next';
 | 
			
		||||
@@ -15,8 +15,6 @@ import { useReactFlow } from '@xyflow/react';
 | 
			
		||||
import type { BaseDialogProps } from '../common/base-dialog-props';
 | 
			
		||||
import { useAlert } from '@/context/alert-context/alert-context';
 | 
			
		||||
import { sqlImportToDiagram } from '@/lib/data/sql-import';
 | 
			
		||||
import { importDBMLToDiagram } from '@/lib/dbml/dbml-import/dbml-import';
 | 
			
		||||
import type { ImportMethod } from '@/lib/import-method/import-method';
 | 
			
		||||
 | 
			
		||||
export interface ImportDatabaseDialogProps extends BaseDialogProps {
 | 
			
		||||
    databaseType: DatabaseType;
 | 
			
		||||
@@ -26,7 +24,7 @@ export const ImportDatabaseDialog: React.FC<ImportDatabaseDialogProps> = ({
 | 
			
		||||
    dialog,
 | 
			
		||||
    databaseType,
 | 
			
		||||
}) => {
 | 
			
		||||
    const [importMethod, setImportMethod] = useState<ImportMethod>('query');
 | 
			
		||||
    const [importMethod, setImportMethod] = useState<'query' | 'ddl'>('query');
 | 
			
		||||
    const { closeImportDatabaseDialog } = useDialog();
 | 
			
		||||
    const { showAlert } = useAlert();
 | 
			
		||||
    const {
 | 
			
		||||
@@ -67,10 +65,6 @@ export const ImportDatabaseDialog: React.FC<ImportDatabaseDialogProps> = ({
 | 
			
		||||
                sourceDatabaseType: databaseType,
 | 
			
		||||
                targetDatabaseType: databaseType,
 | 
			
		||||
            });
 | 
			
		||||
        } else if (importMethod === 'dbml') {
 | 
			
		||||
            diagram = await importDBMLToDiagram(scriptResult, {
 | 
			
		||||
                databaseType,
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            const databaseMetadata: DatabaseMetadata =
 | 
			
		||||
                loadDatabaseMetadata(scriptResult);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										419
									
								
								src/dialogs/import-dbml-dialog/import-dbml-dialog.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										419
									
								
								src/dialogs/import-dbml-dialog/import-dbml-dialog.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,419 @@
 | 
			
		||||
import React, {
 | 
			
		||||
    useCallback,
 | 
			
		||||
    useEffect,
 | 
			
		||||
    useState,
 | 
			
		||||
    Suspense,
 | 
			
		||||
    useRef,
 | 
			
		||||
} from 'react';
 | 
			
		||||
import * as monaco from 'monaco-editor';
 | 
			
		||||
import { useDialog } from '@/hooks/use-dialog';
 | 
			
		||||
import {
 | 
			
		||||
    Dialog,
 | 
			
		||||
    DialogClose,
 | 
			
		||||
    DialogContent,
 | 
			
		||||
    DialogDescription,
 | 
			
		||||
    DialogFooter,
 | 
			
		||||
    DialogHeader,
 | 
			
		||||
    DialogInternalContent,
 | 
			
		||||
    DialogTitle,
 | 
			
		||||
} from '@/components/dialog/dialog';
 | 
			
		||||
import { Button } from '@/components/button/button';
 | 
			
		||||
import type { BaseDialogProps } from '../common/base-dialog-props';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { Editor } from '@/components/code-snippet/code-snippet';
 | 
			
		||||
import { useTheme } from '@/hooks/use-theme';
 | 
			
		||||
import { AlertCircle } from 'lucide-react';
 | 
			
		||||
import {
 | 
			
		||||
    importDBMLToDiagram,
 | 
			
		||||
    sanitizeDBML,
 | 
			
		||||
    preprocessDBML,
 | 
			
		||||
} from '@/lib/dbml/dbml-import/dbml-import';
 | 
			
		||||
import { useChartDB } from '@/hooks/use-chartdb';
 | 
			
		||||
import { Parser } from '@dbml/core';
 | 
			
		||||
import { useCanvas } from '@/hooks/use-canvas';
 | 
			
		||||
import { setupDBMLLanguage } from '@/components/code-snippet/languages/dbml-language';
 | 
			
		||||
import type { DBTable } from '@/lib/domain/db-table';
 | 
			
		||||
import { useToast } from '@/components/toast/use-toast';
 | 
			
		||||
import { Spinner } from '@/components/spinner/spinner';
 | 
			
		||||
import { debounce } from '@/lib/utils';
 | 
			
		||||
 | 
			
		||||
interface DBMLError {
 | 
			
		||||
    message: string;
 | 
			
		||||
    line: number;
 | 
			
		||||
    column: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parseDBMLError(error: unknown): DBMLError | null {
 | 
			
		||||
    try {
 | 
			
		||||
        if (typeof error === 'string') {
 | 
			
		||||
            const parsed = JSON.parse(error);
 | 
			
		||||
            if (parsed.diags?.[0]) {
 | 
			
		||||
                const diag = parsed.diags[0];
 | 
			
		||||
                return {
 | 
			
		||||
                    message: diag.message,
 | 
			
		||||
                    line: diag.location.start.line,
 | 
			
		||||
                    column: diag.location.start.column,
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        } else if (error && typeof error === 'object' && 'diags' in error) {
 | 
			
		||||
            const parsed = error as {
 | 
			
		||||
                diags: Array<{
 | 
			
		||||
                    message: string;
 | 
			
		||||
                    location: { start: { line: number; column: number } };
 | 
			
		||||
                }>;
 | 
			
		||||
            };
 | 
			
		||||
            if (parsed.diags?.[0]) {
 | 
			
		||||
                return {
 | 
			
		||||
                    message: parsed.diags[0].message,
 | 
			
		||||
                    line: parsed.diags[0].location.start.line,
 | 
			
		||||
                    column: parsed.diags[0].location.start.column,
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        console.error('Error parsing DBML error:', e);
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ImportDBMLDialogProps extends BaseDialogProps {
 | 
			
		||||
    withCreateEmptyDiagram?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ImportDBMLDialog: React.FC<ImportDBMLDialogProps> = ({
 | 
			
		||||
    dialog,
 | 
			
		||||
    withCreateEmptyDiagram,
 | 
			
		||||
}) => {
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
    const initialDBML = `// Use DBML to define your database structure
 | 
			
		||||
// Simple Blog System with Comments Example
 | 
			
		||||
 | 
			
		||||
Table users {
 | 
			
		||||
  id integer [primary key]
 | 
			
		||||
  name varchar
 | 
			
		||||
  email varchar
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Table posts {
 | 
			
		||||
  id integer [primary key]
 | 
			
		||||
  title varchar
 | 
			
		||||
  content text
 | 
			
		||||
  user_id integer
 | 
			
		||||
  created_at timestamp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Table comments {
 | 
			
		||||
  id integer [primary key]
 | 
			
		||||
  content text
 | 
			
		||||
  post_id integer
 | 
			
		||||
  user_id integer
 | 
			
		||||
  created_at timestamp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Relationships
 | 
			
		||||
Ref: posts.user_id > users.id // Each post belongs to one user
 | 
			
		||||
Ref: comments.post_id > posts.id // Each comment belongs to one post
 | 
			
		||||
Ref: comments.user_id > users.id // Each comment is written by one user`;
 | 
			
		||||
 | 
			
		||||
    const [dbmlContent, setDBMLContent] = useState<string>(initialDBML);
 | 
			
		||||
    const { closeImportDBMLDialog } = useDialog();
 | 
			
		||||
    const [errorMessage, setErrorMessage] = useState<string | undefined>();
 | 
			
		||||
    const { effectiveTheme } = useTheme();
 | 
			
		||||
    const { toast } = useToast();
 | 
			
		||||
    const {
 | 
			
		||||
        addTables,
 | 
			
		||||
        addRelationships,
 | 
			
		||||
        tables,
 | 
			
		||||
        relationships,
 | 
			
		||||
        removeTables,
 | 
			
		||||
        removeRelationships,
 | 
			
		||||
    } = useChartDB();
 | 
			
		||||
    const { reorderTables } = useCanvas();
 | 
			
		||||
    const [reorder, setReorder] = useState(false);
 | 
			
		||||
    const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
 | 
			
		||||
    const decorationsCollection =
 | 
			
		||||
        useRef<monaco.editor.IEditorDecorationsCollection>();
 | 
			
		||||
 | 
			
		||||
    const handleEditorDidMount = (
 | 
			
		||||
        editor: monaco.editor.IStandaloneCodeEditor
 | 
			
		||||
    ) => {
 | 
			
		||||
        editorRef.current = editor;
 | 
			
		||||
        decorationsCollection.current = editor.createDecorationsCollection();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (reorder) {
 | 
			
		||||
            reorderTables({
 | 
			
		||||
                updateHistory: false,
 | 
			
		||||
            });
 | 
			
		||||
            setReorder(false);
 | 
			
		||||
        }
 | 
			
		||||
    }, [reorder, reorderTables]);
 | 
			
		||||
 | 
			
		||||
    const highlightErrorLine = useCallback((error: DBMLError) => {
 | 
			
		||||
        if (!editorRef.current) return;
 | 
			
		||||
 | 
			
		||||
        const model = editorRef.current.getModel();
 | 
			
		||||
        if (!model) return;
 | 
			
		||||
 | 
			
		||||
        const decorations = [
 | 
			
		||||
            {
 | 
			
		||||
                range: new monaco.Range(
 | 
			
		||||
                    error.line,
 | 
			
		||||
                    1,
 | 
			
		||||
                    error.line,
 | 
			
		||||
                    model.getLineMaxColumn(error.line)
 | 
			
		||||
                ),
 | 
			
		||||
                options: {
 | 
			
		||||
                    isWholeLine: true,
 | 
			
		||||
                    className: 'dbml-error-line',
 | 
			
		||||
                    glyphMarginClassName: 'dbml-error-glyph',
 | 
			
		||||
                    hoverMessage: { value: error.message },
 | 
			
		||||
                    overviewRuler: {
 | 
			
		||||
                        color: '#ff0000',
 | 
			
		||||
                        position: monaco.editor.OverviewRulerLane.Right,
 | 
			
		||||
                        darkColor: '#ff0000',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        decorationsCollection.current?.set(decorations);
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    const clearDecorations = useCallback(() => {
 | 
			
		||||
        decorationsCollection.current?.clear();
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    const validateDBML = useCallback(
 | 
			
		||||
        async (content: string) => {
 | 
			
		||||
            // Clear previous errors
 | 
			
		||||
            setErrorMessage(undefined);
 | 
			
		||||
            clearDecorations();
 | 
			
		||||
 | 
			
		||||
            if (!content.trim()) return;
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                const preprocessedContent = preprocessDBML(content);
 | 
			
		||||
                const sanitizedContent = sanitizeDBML(preprocessedContent);
 | 
			
		||||
                const parser = new Parser();
 | 
			
		||||
                parser.parse(sanitizedContent, 'dbml');
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                const parsedError = parseDBMLError(e);
 | 
			
		||||
                if (parsedError) {
 | 
			
		||||
                    setErrorMessage(
 | 
			
		||||
                        t('import_dbml_dialog.error.description') +
 | 
			
		||||
                            ` (1 error found - in line ${parsedError.line})`
 | 
			
		||||
                    );
 | 
			
		||||
                    highlightErrorLine(parsedError);
 | 
			
		||||
                } else {
 | 
			
		||||
                    setErrorMessage(
 | 
			
		||||
                        e instanceof Error ? e.message : JSON.stringify(e)
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [clearDecorations, highlightErrorLine, t]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const debouncedValidateRef = useRef<((value: string) => void) | null>(null);
 | 
			
		||||
 | 
			
		||||
    // Set up debounced validation
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        debouncedValidateRef.current = debounce((value: string) => {
 | 
			
		||||
            validateDBML(value);
 | 
			
		||||
        }, 500);
 | 
			
		||||
 | 
			
		||||
        return () => {
 | 
			
		||||
            debouncedValidateRef.current = null;
 | 
			
		||||
        };
 | 
			
		||||
    }, [validateDBML]);
 | 
			
		||||
 | 
			
		||||
    // Trigger validation when content changes
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (debouncedValidateRef.current) {
 | 
			
		||||
            debouncedValidateRef.current(dbmlContent);
 | 
			
		||||
        }
 | 
			
		||||
    }, [dbmlContent]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (!dialog.open) {
 | 
			
		||||
            setErrorMessage(undefined);
 | 
			
		||||
            clearDecorations();
 | 
			
		||||
            setDBMLContent(initialDBML);
 | 
			
		||||
        }
 | 
			
		||||
    }, [dialog.open, initialDBML, clearDecorations]);
 | 
			
		||||
 | 
			
		||||
    const handleImport = useCallback(async () => {
 | 
			
		||||
        if (!dbmlContent.trim() || errorMessage) return;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const importedDiagram = await importDBMLToDiagram(dbmlContent);
 | 
			
		||||
            const tableIdsToRemove = tables
 | 
			
		||||
                .filter((table) =>
 | 
			
		||||
                    importedDiagram.tables?.some(
 | 
			
		||||
                        (t: DBTable) =>
 | 
			
		||||
                            t.name === table.name && t.schema === table.schema
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
                .map((table) => table.id);
 | 
			
		||||
            // Find relationships that need to be removed
 | 
			
		||||
            const relationshipIdsToRemove = relationships
 | 
			
		||||
                .filter((relationship) => {
 | 
			
		||||
                    const sourceTable = tables.find(
 | 
			
		||||
                        (table: DBTable) =>
 | 
			
		||||
                            table.id === relationship.sourceTableId
 | 
			
		||||
                    );
 | 
			
		||||
                    const targetTable = tables.find(
 | 
			
		||||
                        (table: DBTable) =>
 | 
			
		||||
                            table.id === relationship.targetTableId
 | 
			
		||||
                    );
 | 
			
		||||
                    if (!sourceTable || !targetTable) return true;
 | 
			
		||||
                    const replacementSourceTable = importedDiagram.tables?.find(
 | 
			
		||||
                        (table: DBTable) =>
 | 
			
		||||
                            table.name === sourceTable.name &&
 | 
			
		||||
                            table.schema === sourceTable.schema
 | 
			
		||||
                    );
 | 
			
		||||
                    const replacementTargetTable = importedDiagram.tables?.find(
 | 
			
		||||
                        (table: DBTable) =>
 | 
			
		||||
                            table.name === targetTable.name &&
 | 
			
		||||
                            table.schema === targetTable.schema
 | 
			
		||||
                    );
 | 
			
		||||
                    return replacementSourceTable || replacementTargetTable;
 | 
			
		||||
                })
 | 
			
		||||
                .map((relationship) => relationship.id);
 | 
			
		||||
 | 
			
		||||
            // Remove existing items
 | 
			
		||||
            await Promise.all([
 | 
			
		||||
                removeTables(tableIdsToRemove, { updateHistory: false }),
 | 
			
		||||
                removeRelationships(relationshipIdsToRemove, {
 | 
			
		||||
                    updateHistory: false,
 | 
			
		||||
                }),
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            // Add new items
 | 
			
		||||
            await Promise.all([
 | 
			
		||||
                addTables(importedDiagram.tables ?? [], {
 | 
			
		||||
                    updateHistory: false,
 | 
			
		||||
                }),
 | 
			
		||||
                addRelationships(importedDiagram.relationships ?? [], {
 | 
			
		||||
                    updateHistory: false,
 | 
			
		||||
                }),
 | 
			
		||||
            ]);
 | 
			
		||||
            setReorder(true);
 | 
			
		||||
            closeImportDBMLDialog();
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            toast({
 | 
			
		||||
                title: t('import_dbml_dialog.error.title'),
 | 
			
		||||
                variant: 'destructive',
 | 
			
		||||
                description: (
 | 
			
		||||
                    <>
 | 
			
		||||
                        <div>{t('import_dbml_dialog.error.description')}</div>
 | 
			
		||||
                        {e instanceof Error ? e.message : JSON.stringify(e)}
 | 
			
		||||
                    </>
 | 
			
		||||
                ),
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }, [
 | 
			
		||||
        dbmlContent,
 | 
			
		||||
        closeImportDBMLDialog,
 | 
			
		||||
        tables,
 | 
			
		||||
        relationships,
 | 
			
		||||
        removeTables,
 | 
			
		||||
        removeRelationships,
 | 
			
		||||
        addTables,
 | 
			
		||||
        addRelationships,
 | 
			
		||||
        errorMessage,
 | 
			
		||||
        toast,
 | 
			
		||||
        setReorder,
 | 
			
		||||
        t,
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <Dialog
 | 
			
		||||
            {...dialog}
 | 
			
		||||
            onOpenChange={(open) => {
 | 
			
		||||
                if (!open) {
 | 
			
		||||
                    closeImportDBMLDialog();
 | 
			
		||||
                }
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            <DialogContent
 | 
			
		||||
                className="flex h-[80vh] max-h-screen w-full flex-col md:max-w-[900px]"
 | 
			
		||||
                showClose
 | 
			
		||||
            >
 | 
			
		||||
                <DialogHeader>
 | 
			
		||||
                    <DialogTitle>
 | 
			
		||||
                        {withCreateEmptyDiagram
 | 
			
		||||
                            ? t('import_dbml_dialog.example_title')
 | 
			
		||||
                            : t('import_dbml_dialog.title')}
 | 
			
		||||
                    </DialogTitle>
 | 
			
		||||
                    <DialogDescription>
 | 
			
		||||
                        {t('import_dbml_dialog.description')}
 | 
			
		||||
                    </DialogDescription>
 | 
			
		||||
                </DialogHeader>
 | 
			
		||||
                <DialogInternalContent>
 | 
			
		||||
                    <Suspense fallback={<Spinner />}>
 | 
			
		||||
                        <Editor
 | 
			
		||||
                            value={dbmlContent}
 | 
			
		||||
                            onChange={(value) => setDBMLContent(value || '')}
 | 
			
		||||
                            language="dbml"
 | 
			
		||||
                            onMount={handleEditorDidMount}
 | 
			
		||||
                            theme={
 | 
			
		||||
                                effectiveTheme === 'dark'
 | 
			
		||||
                                    ? 'dbml-dark'
 | 
			
		||||
                                    : 'dbml-light'
 | 
			
		||||
                            }
 | 
			
		||||
                            beforeMount={setupDBMLLanguage}
 | 
			
		||||
                            options={{
 | 
			
		||||
                                minimap: { enabled: false },
 | 
			
		||||
                                scrollBeyondLastLine: false,
 | 
			
		||||
                                automaticLayout: true,
 | 
			
		||||
                                glyphMargin: true,
 | 
			
		||||
                                lineNumbers: 'on',
 | 
			
		||||
                                scrollbar: {
 | 
			
		||||
                                    vertical: 'visible',
 | 
			
		||||
                                    horizontal: 'visible',
 | 
			
		||||
                                },
 | 
			
		||||
                            }}
 | 
			
		||||
                            className="size-full"
 | 
			
		||||
                        />
 | 
			
		||||
                    </Suspense>
 | 
			
		||||
                </DialogInternalContent>
 | 
			
		||||
                <DialogFooter>
 | 
			
		||||
                    <div className="flex w-full items-center justify-between">
 | 
			
		||||
                        <div className="flex items-center gap-4">
 | 
			
		||||
                            <DialogClose asChild>
 | 
			
		||||
                                <Button variant="secondary">
 | 
			
		||||
                                    {withCreateEmptyDiagram
 | 
			
		||||
                                        ? t('import_dbml_dialog.skip_and_empty')
 | 
			
		||||
                                        : t('import_dbml_dialog.cancel')}
 | 
			
		||||
                                </Button>
 | 
			
		||||
                            </DialogClose>
 | 
			
		||||
                            {errorMessage ? (
 | 
			
		||||
                                <div className="flex items-center gap-1">
 | 
			
		||||
                                    <AlertCircle className="size-4 text-destructive" />
 | 
			
		||||
 | 
			
		||||
                                    <span className="text-xs text-destructive">
 | 
			
		||||
                                        {errorMessage ||
 | 
			
		||||
                                            t(
 | 
			
		||||
                                                'import_dbml_dialog.error.description'
 | 
			
		||||
                                            )}
 | 
			
		||||
                                    </span>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            ) : null}
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <Button
 | 
			
		||||
                            onClick={handleImport}
 | 
			
		||||
                            disabled={!dbmlContent.trim() || !!errorMessage}
 | 
			
		||||
                        >
 | 
			
		||||
                            {withCreateEmptyDiagram
 | 
			
		||||
                                ? t('import_dbml_dialog.show_example')
 | 
			
		||||
                                : t('import_dbml_dialog.import')}
 | 
			
		||||
                        </Button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </DialogFooter>
 | 
			
		||||
            </DialogContent>
 | 
			
		||||
        </Dialog>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@@ -1,98 +0,0 @@
 | 
			
		||||
import React, { useCallback } from 'react';
 | 
			
		||||
import {
 | 
			
		||||
    DropdownMenu,
 | 
			
		||||
    DropdownMenuContent,
 | 
			
		||||
    DropdownMenuItem,
 | 
			
		||||
    DropdownMenuSeparator,
 | 
			
		||||
    DropdownMenuTrigger,
 | 
			
		||||
} from '@/components/dropdown-menu/dropdown-menu';
 | 
			
		||||
import { Button } from '@/components/button/button';
 | 
			
		||||
import { Ellipsis, Layers2, SquareArrowOutUpRight, Trash2 } from 'lucide-react';
 | 
			
		||||
import { useChartDB } from '@/hooks/use-chartdb';
 | 
			
		||||
import type { Diagram } from '@/lib/domain';
 | 
			
		||||
import { useStorage } from '@/hooks/use-storage';
 | 
			
		||||
import { cloneDiagram } from '@/lib/clone';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
 | 
			
		||||
interface DiagramRowActionsMenuProps {
 | 
			
		||||
    diagram: Diagram;
 | 
			
		||||
    onOpen: () => void;
 | 
			
		||||
    refetch: () => void;
 | 
			
		||||
    numberOfDiagrams: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const DiagramRowActionsMenu: React.FC<DiagramRowActionsMenuProps> = ({
 | 
			
		||||
    diagram,
 | 
			
		||||
    onOpen,
 | 
			
		||||
    refetch,
 | 
			
		||||
    numberOfDiagrams,
 | 
			
		||||
}) => {
 | 
			
		||||
    const { diagramId } = useChartDB();
 | 
			
		||||
    const { deleteDiagram, addDiagram } = useStorage();
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
 | 
			
		||||
    const onDelete = useCallback(async () => {
 | 
			
		||||
        deleteDiagram(diagram.id);
 | 
			
		||||
        refetch();
 | 
			
		||||
 | 
			
		||||
        if (diagram.id === diagramId || numberOfDiagrams <= 1) {
 | 
			
		||||
            window.location.href = '/';
 | 
			
		||||
        }
 | 
			
		||||
    }, [deleteDiagram, diagram.id, diagramId, refetch, numberOfDiagrams]);
 | 
			
		||||
 | 
			
		||||
    const onDuplicate = useCallback(async () => {
 | 
			
		||||
        const duplicatedDiagram = cloneDiagram(diagram);
 | 
			
		||||
 | 
			
		||||
        const diagramToAdd = duplicatedDiagram.diagram;
 | 
			
		||||
 | 
			
		||||
        if (!diagramToAdd) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        diagramToAdd.name = `${diagram.name} (Copy)`;
 | 
			
		||||
 | 
			
		||||
        addDiagram({ diagram: diagramToAdd });
 | 
			
		||||
        refetch();
 | 
			
		||||
    }, [addDiagram, refetch, diagram]);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <DropdownMenu>
 | 
			
		||||
            <DropdownMenuTrigger asChild>
 | 
			
		||||
                <Button
 | 
			
		||||
                    variant="ghost"
 | 
			
		||||
                    size="icon"
 | 
			
		||||
                    className="size-8 p-0"
 | 
			
		||||
                    onClick={(e) => e.stopPropagation()}
 | 
			
		||||
                >
 | 
			
		||||
                    <Ellipsis className="size-4" />
 | 
			
		||||
                </Button>
 | 
			
		||||
            </DropdownMenuTrigger>
 | 
			
		||||
            <DropdownMenuContent align="end">
 | 
			
		||||
                <DropdownMenuItem
 | 
			
		||||
                    onClick={onOpen}
 | 
			
		||||
                    className="flex justify-between gap-4"
 | 
			
		||||
                >
 | 
			
		||||
                    {t('open_diagram_dialog.diagram_actions.open')}
 | 
			
		||||
                    <SquareArrowOutUpRight className="size-3.5" />
 | 
			
		||||
                </DropdownMenuItem>
 | 
			
		||||
 | 
			
		||||
                <DropdownMenuItem
 | 
			
		||||
                    onClick={onDuplicate}
 | 
			
		||||
                    className="flex justify-between gap-4"
 | 
			
		||||
                >
 | 
			
		||||
                    {t('open_diagram_dialog.diagram_actions.duplicate')}
 | 
			
		||||
                    <Layers2 className="size-3.5" />
 | 
			
		||||
                </DropdownMenuItem>
 | 
			
		||||
 | 
			
		||||
                <DropdownMenuSeparator />
 | 
			
		||||
                <DropdownMenuItem
 | 
			
		||||
                    onClick={onDelete}
 | 
			
		||||
                    className="flex justify-between gap-4 text-red-700"
 | 
			
		||||
                >
 | 
			
		||||
                    {t('open_diagram_dialog.diagram_actions.delete')}
 | 
			
		||||
                    <Trash2 className="size-3.5 text-red-700" />
 | 
			
		||||
                </DropdownMenuItem>
 | 
			
		||||
            </DropdownMenuContent>
 | 
			
		||||
        </DropdownMenu>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
@@ -27,7 +27,6 @@ import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useNavigate } from 'react-router-dom';
 | 
			
		||||
import type { BaseDialogProps } from '../common/base-dialog-props';
 | 
			
		||||
import { useDebounce } from '@/hooks/use-debounce';
 | 
			
		||||
import { DiagramRowActionsMenu } from './diagram-row-actions-menu/diagram-row-actions-menu';
 | 
			
		||||
 | 
			
		||||
export interface OpenDiagramDialogProps extends BaseDialogProps {
 | 
			
		||||
    canClose?: boolean;
 | 
			
		||||
@@ -47,22 +46,21 @@ export const OpenDiagramDialog: React.FC<OpenDiagramDialogProps> = ({
 | 
			
		||||
        string | undefined
 | 
			
		||||
    >();
 | 
			
		||||
 | 
			
		||||
    const fetchDiagrams = useCallback(async () => {
 | 
			
		||||
        const diagrams = await listDiagrams({ includeTables: true });
 | 
			
		||||
        setDiagrams(
 | 
			
		||||
            diagrams.sort(
 | 
			
		||||
                (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }, [listDiagrams]);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        setSelectedDiagramId(undefined);
 | 
			
		||||
    }, [dialog.open]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (!dialog.open) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        setSelectedDiagramId(undefined);
 | 
			
		||||
        const fetchDiagrams = async () => {
 | 
			
		||||
            const diagrams = await listDiagrams({ includeTables: true });
 | 
			
		||||
            setDiagrams(
 | 
			
		||||
                diagrams.sort(
 | 
			
		||||
                    (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
        };
 | 
			
		||||
        fetchDiagrams();
 | 
			
		||||
    }, [dialog.open, fetchDiagrams]);
 | 
			
		||||
    }, [listDiagrams, setDiagrams, dialog.open]);
 | 
			
		||||
 | 
			
		||||
    const openDiagram = useCallback(
 | 
			
		||||
        (diagramId: string) => {
 | 
			
		||||
@@ -168,7 +166,6 @@ export const OpenDiagramDialog: React.FC<OpenDiagramDialogProps> = ({
 | 
			
		||||
                                            'open_diagram_dialog.table_columns.tables_count'
 | 
			
		||||
                                        )}
 | 
			
		||||
                                    </TableHead>
 | 
			
		||||
                                    <TableHead />
 | 
			
		||||
                                </TableRow>
 | 
			
		||||
                            </TableHeader>
 | 
			
		||||
                            <TableBody>
 | 
			
		||||
@@ -224,19 +221,6 @@ export const OpenDiagramDialog: React.FC<OpenDiagramDialogProps> = ({
 | 
			
		||||
                                        <TableCell className="text-center">
 | 
			
		||||
                                            {diagram.tables?.length}
 | 
			
		||||
                                        </TableCell>
 | 
			
		||||
                                        <TableCell className="items-center p-0 pr-1 text-right">
 | 
			
		||||
                                            <DiagramRowActionsMenu
 | 
			
		||||
                                                diagram={diagram}
 | 
			
		||||
                                                onOpen={() => {
 | 
			
		||||
                                                    openDiagram(diagram.id);
 | 
			
		||||
                                                    closeOpenDiagramDialog();
 | 
			
		||||
                                                }}
 | 
			
		||||
                                                numberOfDiagrams={
 | 
			
		||||
                                                    diagrams.length
 | 
			
		||||
                                                }
 | 
			
		||||
                                                refetch={fetchDiagrams}
 | 
			
		||||
                                            />
 | 
			
		||||
                                        </TableCell>
 | 
			
		||||
                                    </TableRow>
 | 
			
		||||
                                ))}
 | 
			
		||||
                            </TableBody>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
 | 
			
		||||
import React, { useCallback, useEffect, useMemo } from 'react';
 | 
			
		||||
import { useDialog } from '@/hooks/use-dialog';
 | 
			
		||||
import {
 | 
			
		||||
    Dialog,
 | 
			
		||||
@@ -17,23 +17,11 @@ import type { DBSchema } from '@/lib/domain/db-schema';
 | 
			
		||||
import { schemaNameToSchemaId } from '@/lib/domain/db-schema';
 | 
			
		||||
import type { BaseDialogProps } from '../common/base-dialog-props';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { Input } from '@/components/input/input';
 | 
			
		||||
import { Separator } from '@/components/separator/separator';
 | 
			
		||||
import { Group, SquarePlus } from 'lucide-react';
 | 
			
		||||
import {
 | 
			
		||||
    Tooltip,
 | 
			
		||||
    TooltipContent,
 | 
			
		||||
    TooltipTrigger,
 | 
			
		||||
} from '@/components/tooltip/tooltip';
 | 
			
		||||
import { useChartDB } from '@/hooks/use-chartdb';
 | 
			
		||||
import { defaultSchemas } from '@/lib/data/default-schemas';
 | 
			
		||||
import { Label } from '@/components/label/label';
 | 
			
		||||
 | 
			
		||||
export interface TableSchemaDialogProps extends BaseDialogProps {
 | 
			
		||||
    table?: DBTable;
 | 
			
		||||
    schemas: DBSchema[];
 | 
			
		||||
    onConfirm: ({ schema }: { schema: DBSchema }) => void;
 | 
			
		||||
    allowSchemaCreation?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const TableSchemaDialog: React.FC<TableSchemaDialogProps> = ({
 | 
			
		||||
@@ -41,32 +29,13 @@ export const TableSchemaDialog: React.FC<TableSchemaDialogProps> = ({
 | 
			
		||||
    table,
 | 
			
		||||
    schemas,
 | 
			
		||||
    onConfirm,
 | 
			
		||||
    allowSchemaCreation = false,
 | 
			
		||||
}) => {
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
    const { databaseType } = useChartDB();
 | 
			
		||||
    const [selectedSchemaId, setSelectedSchemaId] = useState<string>(
 | 
			
		||||
    const [selectedSchemaId, setSelectedSchemaId] = React.useState<string>(
 | 
			
		||||
        table?.schema
 | 
			
		||||
            ? schemaNameToSchemaId(table.schema)
 | 
			
		||||
            : (schemas?.[0]?.id ?? '')
 | 
			
		||||
    );
 | 
			
		||||
    const allowSchemaSelection = useMemo(
 | 
			
		||||
        () => schemas && schemas.length > 0,
 | 
			
		||||
        [schemas]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const defaultSchemaName = useMemo(
 | 
			
		||||
        () => defaultSchemas?.[databaseType],
 | 
			
		||||
        [databaseType]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const [isCreatingNew, setIsCreatingNew] =
 | 
			
		||||
        useState<boolean>(!allowSchemaSelection);
 | 
			
		||||
    const [newSchemaName, setNewSchemaName] = useState<string>(
 | 
			
		||||
        allowSchemaCreation && !allowSchemaSelection
 | 
			
		||||
            ? (defaultSchemaName ?? '')
 | 
			
		||||
            : ''
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (!dialog.open) return;
 | 
			
		||||
@@ -75,39 +44,15 @@ export const TableSchemaDialog: React.FC<TableSchemaDialogProps> = ({
 | 
			
		||||
                ? schemaNameToSchemaId(table.schema)
 | 
			
		||||
                : (schemas?.[0]?.id ?? '')
 | 
			
		||||
        );
 | 
			
		||||
        setIsCreatingNew(!allowSchemaSelection);
 | 
			
		||||
        setNewSchemaName(
 | 
			
		||||
            allowSchemaCreation && !allowSchemaSelection
 | 
			
		||||
                ? (defaultSchemaName ?? '')
 | 
			
		||||
                : ''
 | 
			
		||||
        );
 | 
			
		||||
    }, [
 | 
			
		||||
        defaultSchemaName,
 | 
			
		||||
        dialog.open,
 | 
			
		||||
        schemas,
 | 
			
		||||
        table?.schema,
 | 
			
		||||
        allowSchemaSelection,
 | 
			
		||||
        allowSchemaCreation,
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    }, [dialog.open, schemas, table?.schema]);
 | 
			
		||||
    const { closeTableSchemaDialog } = useDialog();
 | 
			
		||||
 | 
			
		||||
    const handleConfirm = useCallback(() => {
 | 
			
		||||
        if (isCreatingNew && newSchemaName.trim()) {
 | 
			
		||||
            const newSchema: DBSchema = {
 | 
			
		||||
                id: schemaNameToSchemaId(newSchemaName.trim()),
 | 
			
		||||
                name: newSchemaName.trim(),
 | 
			
		||||
                tableCount: 0,
 | 
			
		||||
            };
 | 
			
		||||
        const schema = schemas.find((s) => s.id === selectedSchemaId);
 | 
			
		||||
        if (!schema) return;
 | 
			
		||||
 | 
			
		||||
            onConfirm({ schema: newSchema });
 | 
			
		||||
        } else {
 | 
			
		||||
            const schema = schemas.find((s) => s.id === selectedSchemaId);
 | 
			
		||||
            if (!schema) return;
 | 
			
		||||
 | 
			
		||||
            onConfirm({ schema });
 | 
			
		||||
        }
 | 
			
		||||
    }, [onConfirm, selectedSchemaId, schemas, isCreatingNew, newSchemaName]);
 | 
			
		||||
        onConfirm({ schema });
 | 
			
		||||
    }, [onConfirm, selectedSchemaId, schemas]);
 | 
			
		||||
 | 
			
		||||
    const schemaOptions: SelectBoxOption[] = useMemo(
 | 
			
		||||
        () =>
 | 
			
		||||
@@ -118,25 +63,6 @@ export const TableSchemaDialog: React.FC<TableSchemaDialogProps> = ({
 | 
			
		||||
        [schemas]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const renderSwitchCreateOrSelectButton = useCallback(
 | 
			
		||||
        () => (
 | 
			
		||||
            <Button
 | 
			
		||||
                variant="outline"
 | 
			
		||||
                className="w-full justify-start"
 | 
			
		||||
                onClick={() => setIsCreatingNew(!isCreatingNew)}
 | 
			
		||||
                disabled={!allowSchemaSelection || !allowSchemaCreation}
 | 
			
		||||
            >
 | 
			
		||||
                {!isCreatingNew ? (
 | 
			
		||||
                    <SquarePlus className="mr-2 size-4 " />
 | 
			
		||||
                ) : (
 | 
			
		||||
                    <Group className="mr-2 size-4 " />
 | 
			
		||||
                )}
 | 
			
		||||
                {isCreatingNew ? 'Select existing schema' : 'Create new schema'}
 | 
			
		||||
            </Button>
 | 
			
		||||
        ),
 | 
			
		||||
        [isCreatingNew, allowSchemaSelection, allowSchemaCreation]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <Dialog
 | 
			
		||||
            {...dialog}
 | 
			
		||||
@@ -144,106 +70,48 @@ export const TableSchemaDialog: React.FC<TableSchemaDialogProps> = ({
 | 
			
		||||
                if (!open) {
 | 
			
		||||
                    closeTableSchemaDialog();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                setTimeout(() => (document.body.style.pointerEvents = ''), 500);
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            <DialogContent className="flex flex-col" showClose>
 | 
			
		||||
                <DialogHeader>
 | 
			
		||||
                    <DialogTitle>
 | 
			
		||||
                        {!allowSchemaSelection && allowSchemaCreation
 | 
			
		||||
                            ? t('create_table_schema_dialog.title')
 | 
			
		||||
                            : table
 | 
			
		||||
                              ? t('update_table_schema_dialog.title')
 | 
			
		||||
                              : t('new_table_schema_dialog.title')}
 | 
			
		||||
                        {table
 | 
			
		||||
                            ? t('update_table_schema_dialog.title')
 | 
			
		||||
                            : t('new_table_schema_dialog.title')}
 | 
			
		||||
                    </DialogTitle>
 | 
			
		||||
                    <DialogDescription>
 | 
			
		||||
                        {!allowSchemaSelection && allowSchemaCreation
 | 
			
		||||
                            ? t('create_table_schema_dialog.description')
 | 
			
		||||
                            : table
 | 
			
		||||
                              ? t('update_table_schema_dialog.description', {
 | 
			
		||||
                                    tableName: table.name,
 | 
			
		||||
                                })
 | 
			
		||||
                              : t('new_table_schema_dialog.description')}
 | 
			
		||||
                        {table
 | 
			
		||||
                            ? t('update_table_schema_dialog.description', {
 | 
			
		||||
                                  tableName: table.name,
 | 
			
		||||
                              })
 | 
			
		||||
                            : t('new_table_schema_dialog.description')}
 | 
			
		||||
                    </DialogDescription>
 | 
			
		||||
                </DialogHeader>
 | 
			
		||||
                <div className="grid gap-4 py-1">
 | 
			
		||||
                    <div className="grid w-full items-center gap-4">
 | 
			
		||||
                        {!isCreatingNew ? (
 | 
			
		||||
                            <SelectBox
 | 
			
		||||
                                options={schemaOptions}
 | 
			
		||||
                                multiple={false}
 | 
			
		||||
                                value={selectedSchemaId}
 | 
			
		||||
                                onChange={(value) =>
 | 
			
		||||
                                    setSelectedSchemaId(value as string)
 | 
			
		||||
                                }
 | 
			
		||||
                            />
 | 
			
		||||
                        ) : (
 | 
			
		||||
                            <div className="flex flex-col gap-2">
 | 
			
		||||
                                {allowSchemaCreation &&
 | 
			
		||||
                                !allowSchemaSelection ? (
 | 
			
		||||
                                    <Label htmlFor="new-schema-name">
 | 
			
		||||
                                        Schema Name
 | 
			
		||||
                                    </Label>
 | 
			
		||||
                                ) : null}
 | 
			
		||||
                                <Input
 | 
			
		||||
                                    id="new-schema-name"
 | 
			
		||||
                                    value={newSchemaName}
 | 
			
		||||
                                    onChange={(e) =>
 | 
			
		||||
                                        setNewSchemaName(e.target.value)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    placeholder={`Enter schema name.${defaultSchemaName ? ` e.g. ${defaultSchemaName}.` : ''}`}
 | 
			
		||||
                                    autoFocus
 | 
			
		||||
                                />
 | 
			
		||||
                            </div>
 | 
			
		||||
                        )}
 | 
			
		||||
 | 
			
		||||
                        {allowSchemaCreation && allowSchemaSelection ? (
 | 
			
		||||
                            <>
 | 
			
		||||
                                <div className="relative">
 | 
			
		||||
                                    <Separator className="my-2" />
 | 
			
		||||
                                    <span className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-background px-2 text-xs text-muted-foreground">
 | 
			
		||||
                                        or
 | 
			
		||||
                                    </span>
 | 
			
		||||
                                </div>
 | 
			
		||||
                                {allowSchemaSelection ? (
 | 
			
		||||
                                    renderSwitchCreateOrSelectButton()
 | 
			
		||||
                                ) : (
 | 
			
		||||
                                    <Tooltip>
 | 
			
		||||
                                        <TooltipTrigger asChild>
 | 
			
		||||
                                            <span>
 | 
			
		||||
                                                {renderSwitchCreateOrSelectButton()}
 | 
			
		||||
                                            </span>
 | 
			
		||||
                                        </TooltipTrigger>
 | 
			
		||||
                                        <TooltipContent>
 | 
			
		||||
                                            <p>No existing schemas available</p>
 | 
			
		||||
                                        </TooltipContent>
 | 
			
		||||
                                    </Tooltip>
 | 
			
		||||
                                )}
 | 
			
		||||
                            </>
 | 
			
		||||
                        ) : null}
 | 
			
		||||
                        <SelectBox
 | 
			
		||||
                            options={schemaOptions}
 | 
			
		||||
                            multiple={false}
 | 
			
		||||
                            value={selectedSchemaId}
 | 
			
		||||
                            onChange={(value) =>
 | 
			
		||||
                                setSelectedSchemaId(value as string)
 | 
			
		||||
                            }
 | 
			
		||||
                        />
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <DialogFooter className="flex gap-1 md:justify-between">
 | 
			
		||||
                    <DialogClose asChild>
 | 
			
		||||
                        <Button variant="secondary">
 | 
			
		||||
                            {isCreatingNew
 | 
			
		||||
                                ? t('create_table_schema_dialog.cancel')
 | 
			
		||||
                                : table
 | 
			
		||||
                                  ? t('update_table_schema_dialog.cancel')
 | 
			
		||||
                                  : t('new_table_schema_dialog.cancel')}
 | 
			
		||||
                            {table
 | 
			
		||||
                                ? t('update_table_schema_dialog.cancel')
 | 
			
		||||
                                : t('new_table_schema_dialog.cancel')}
 | 
			
		||||
                        </Button>
 | 
			
		||||
                    </DialogClose>
 | 
			
		||||
                    <DialogClose asChild>
 | 
			
		||||
                        <Button
 | 
			
		||||
                            onClick={handleConfirm}
 | 
			
		||||
                            disabled={isCreatingNew && !newSchemaName.trim()}
 | 
			
		||||
                        >
 | 
			
		||||
                            {isCreatingNew
 | 
			
		||||
                                ? t('create_table_schema_dialog.create')
 | 
			
		||||
                                : table
 | 
			
		||||
                                  ? t('update_table_schema_dialog.confirm')
 | 
			
		||||
                                  : t('new_table_schema_dialog.confirm')}
 | 
			
		||||
                        <Button onClick={handleConfirm}>
 | 
			
		||||
                            {table
 | 
			
		||||
                                ? t('update_table_schema_dialog.confirm')
 | 
			
		||||
                                : t('new_table_schema_dialog.confirm')}
 | 
			
		||||
                        </Button>
 | 
			
		||||
                    </DialogClose>
 | 
			
		||||
                </DialogFooter>
 | 
			
		||||
 
 | 
			
		||||
@@ -83,7 +83,6 @@
 | 
			
		||||
    }
 | 
			
		||||
    body {
 | 
			
		||||
        @apply bg-background text-foreground;
 | 
			
		||||
        overscroll-behavior-x: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .text-editable {
 | 
			
		||||
@@ -155,29 +154,3 @@
 | 
			
		||||
        background-size: 650%;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Edit button emphasis animation */
 | 
			
		||||
@keyframes dbml_edit-button-emphasis {
 | 
			
		||||
    0% {
 | 
			
		||||
        transform: scale(1);
 | 
			
		||||
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.7);
 | 
			
		||||
        background-color: rgba(59, 130, 246, 0);
 | 
			
		||||
    }
 | 
			
		||||
    50% {
 | 
			
		||||
        transform: scale(1.1);
 | 
			
		||||
        box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
 | 
			
		||||
        background-color: rgba(59, 130, 246, 0.1);
 | 
			
		||||
    }
 | 
			
		||||
    100% {
 | 
			
		||||
        transform: scale(1);
 | 
			
		||||
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
 | 
			
		||||
        background-color: rgba(59, 130, 246, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dbml-edit-button-emphasis {
 | 
			
		||||
    animation: dbml_edit-button-emphasis 0.6s ease-in-out;
 | 
			
		||||
    animation-iteration-count: 1;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    z-index: 10;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,181 +0,0 @@
 | 
			
		||||
import { useCallback } from 'react';
 | 
			
		||||
import { useReactFlow } from '@xyflow/react';
 | 
			
		||||
import { useLayout } from '@/hooks/use-layout';
 | 
			
		||||
import { useBreakpoint } from '@/hooks/use-breakpoint';
 | 
			
		||||
 | 
			
		||||
interface FocusOptions {
 | 
			
		||||
    select?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useFocusOn = () => {
 | 
			
		||||
    const { fitView, setNodes, setEdges } = useReactFlow();
 | 
			
		||||
    const { hideSidePanel } = useLayout();
 | 
			
		||||
    const { isMd: isDesktop } = useBreakpoint('md');
 | 
			
		||||
 | 
			
		||||
    const focusOnArea = useCallback(
 | 
			
		||||
        (areaId: string, options: FocusOptions = {}) => {
 | 
			
		||||
            const { select = true } = options;
 | 
			
		||||
 | 
			
		||||
            if (select) {
 | 
			
		||||
                setNodes((nodes) =>
 | 
			
		||||
                    nodes.map((node) =>
 | 
			
		||||
                        node.id === areaId
 | 
			
		||||
                            ? {
 | 
			
		||||
                                  ...node,
 | 
			
		||||
                                  selected: true,
 | 
			
		||||
                              }
 | 
			
		||||
                            : {
 | 
			
		||||
                                  ...node,
 | 
			
		||||
                                  selected: false,
 | 
			
		||||
                              }
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fitView({
 | 
			
		||||
                duration: 500,
 | 
			
		||||
                maxZoom: 1,
 | 
			
		||||
                minZoom: 1,
 | 
			
		||||
                nodes: [
 | 
			
		||||
                    {
 | 
			
		||||
                        id: areaId,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (!isDesktop) {
 | 
			
		||||
                hideSidePanel();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [fitView, setNodes, hideSidePanel, isDesktop]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const focusOnTable = useCallback(
 | 
			
		||||
        (tableId: string, options: FocusOptions = {}) => {
 | 
			
		||||
            const { select = true } = options;
 | 
			
		||||
 | 
			
		||||
            if (select) {
 | 
			
		||||
                setNodes((nodes) =>
 | 
			
		||||
                    nodes.map((node) =>
 | 
			
		||||
                        node.id === tableId
 | 
			
		||||
                            ? {
 | 
			
		||||
                                  ...node,
 | 
			
		||||
                                  selected: true,
 | 
			
		||||
                              }
 | 
			
		||||
                            : {
 | 
			
		||||
                                  ...node,
 | 
			
		||||
                                  selected: false,
 | 
			
		||||
                              }
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fitView({
 | 
			
		||||
                duration: 500,
 | 
			
		||||
                maxZoom: 1,
 | 
			
		||||
                minZoom: 1,
 | 
			
		||||
                nodes: [
 | 
			
		||||
                    {
 | 
			
		||||
                        id: tableId,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (!isDesktop) {
 | 
			
		||||
                hideSidePanel();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [fitView, setNodes, hideSidePanel, isDesktop]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const focusOnNote = useCallback(
 | 
			
		||||
        (noteId: string, options: FocusOptions = {}) => {
 | 
			
		||||
            const { select = true } = options;
 | 
			
		||||
 | 
			
		||||
            if (select) {
 | 
			
		||||
                setNodes((nodes) =>
 | 
			
		||||
                    nodes.map((node) =>
 | 
			
		||||
                        node.id === noteId
 | 
			
		||||
                            ? {
 | 
			
		||||
                                  ...node,
 | 
			
		||||
                                  selected: true,
 | 
			
		||||
                              }
 | 
			
		||||
                            : {
 | 
			
		||||
                                  ...node,
 | 
			
		||||
                                  selected: false,
 | 
			
		||||
                              }
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fitView({
 | 
			
		||||
                duration: 500,
 | 
			
		||||
                maxZoom: 1,
 | 
			
		||||
                minZoom: 1,
 | 
			
		||||
                nodes: [
 | 
			
		||||
                    {
 | 
			
		||||
                        id: noteId,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (!isDesktop) {
 | 
			
		||||
                hideSidePanel();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [fitView, setNodes, hideSidePanel, isDesktop]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const focusOnRelationship = useCallback(
 | 
			
		||||
        (
 | 
			
		||||
            relationshipId: string,
 | 
			
		||||
            sourceTableId: string,
 | 
			
		||||
            targetTableId: string,
 | 
			
		||||
            options: FocusOptions = {}
 | 
			
		||||
        ) => {
 | 
			
		||||
            const { select = true } = options;
 | 
			
		||||
 | 
			
		||||
            if (select) {
 | 
			
		||||
                setEdges((edges) =>
 | 
			
		||||
                    edges.map((edge) =>
 | 
			
		||||
                        edge.id === relationshipId
 | 
			
		||||
                            ? {
 | 
			
		||||
                                  ...edge,
 | 
			
		||||
                                  selected: true,
 | 
			
		||||
                              }
 | 
			
		||||
                            : {
 | 
			
		||||
                                  ...edge,
 | 
			
		||||
                                  selected: false,
 | 
			
		||||
                              }
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fitView({
 | 
			
		||||
                duration: 500,
 | 
			
		||||
                maxZoom: 1,
 | 
			
		||||
                minZoom: 1,
 | 
			
		||||
                nodes: [
 | 
			
		||||
                    {
 | 
			
		||||
                        id: sourceTableId,
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        id: targetTableId,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (!isDesktop) {
 | 
			
		||||
                hideSidePanel();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [fitView, setEdges, hideSidePanel, isDesktop]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        focusOnArea,
 | 
			
		||||
        focusOnTable,
 | 
			
		||||
        focusOnNote,
 | 
			
		||||
        focusOnRelationship,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
@@ -1,379 +0,0 @@
 | 
			
		||||
import { useCallback, useMemo, useState, useEffect, useRef } from 'react';
 | 
			
		||||
import { useChartDB } from './use-chartdb';
 | 
			
		||||
import { useDebounce } from './use-debounce-v2';
 | 
			
		||||
import type { DatabaseType, DBField, DBTable } from '@/lib/domain';
 | 
			
		||||
import type {
 | 
			
		||||
    SelectBoxOption,
 | 
			
		||||
    SelectBoxProps,
 | 
			
		||||
} from '@/components/select-box/select-box';
 | 
			
		||||
import {
 | 
			
		||||
    dataTypeDataToDataType,
 | 
			
		||||
    sortedDataTypeMap,
 | 
			
		||||
    supportsArrayDataType,
 | 
			
		||||
    autoIncrementAlwaysOn,
 | 
			
		||||
    requiresNotNull,
 | 
			
		||||
} from '@/lib/data/data-types/data-types';
 | 
			
		||||
import { generateDBFieldSuffix } from '@/lib/domain/db-field';
 | 
			
		||||
import type { DataTypeData } from '@/lib/data/data-types/data-types';
 | 
			
		||||
 | 
			
		||||
const generateFieldRegexPatterns = (
 | 
			
		||||
    dataType: DataTypeData,
 | 
			
		||||
    databaseType: DatabaseType
 | 
			
		||||
): {
 | 
			
		||||
    regex?: string;
 | 
			
		||||
    extractRegex?: RegExp;
 | 
			
		||||
} => {
 | 
			
		||||
    const typeName = dataType.name;
 | 
			
		||||
    const supportsArrays = supportsArrayDataType(dataType.id, databaseType);
 | 
			
		||||
    const arrayPattern = supportsArrays ? '(\\[\\])?' : '';
 | 
			
		||||
 | 
			
		||||
    if (!dataType.fieldAttributes) {
 | 
			
		||||
        // For types without field attributes, support plain type + optional array notation
 | 
			
		||||
        return {
 | 
			
		||||
            regex: `^${typeName}${arrayPattern}$`,
 | 
			
		||||
            extractRegex: new RegExp(`^${typeName}${arrayPattern}$`),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const fieldAttributes = dataType.fieldAttributes;
 | 
			
		||||
 | 
			
		||||
    if (fieldAttributes.hasCharMaxLength) {
 | 
			
		||||
        if (fieldAttributes.hasCharMaxLengthOption) {
 | 
			
		||||
            return {
 | 
			
		||||
                regex: `^${typeName}\\((\\d+|[mM][aA][xX])\\)${arrayPattern}$`,
 | 
			
		||||
                extractRegex: supportsArrays
 | 
			
		||||
                    ? /\((\d+|max)\)(\[\])?/i
 | 
			
		||||
                    : /\((\d+|max)\)/i,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        return {
 | 
			
		||||
            regex: `^${typeName}\\(\\d+\\)${arrayPattern}$`,
 | 
			
		||||
            extractRegex: supportsArrays ? /\((\d+)\)(\[\])?/ : /\((\d+)\)/,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fieldAttributes.precision && fieldAttributes.scale) {
 | 
			
		||||
        return {
 | 
			
		||||
            regex: `^${typeName}\\s*\\(\\s*\\d+\\s*(?:,\\s*\\d+\\s*)?\\)${arrayPattern}$`,
 | 
			
		||||
            extractRegex: new RegExp(
 | 
			
		||||
                `${typeName}\\s*\\(\\s*(\\d+)\\s*(?:,\\s*(\\d+)\\s*)?\\)${arrayPattern}`
 | 
			
		||||
            ),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fieldAttributes.precision) {
 | 
			
		||||
        return {
 | 
			
		||||
            regex: `^${typeName}\\s*\\(\\s*\\d+\\s*\\)${arrayPattern}$`,
 | 
			
		||||
            extractRegex: supportsArrays ? /\((\d+)\)(\[\])?/ : /\((\d+)\)/,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return { regex: undefined, extractRegex: undefined };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useUpdateTableField = (
 | 
			
		||||
    table: DBTable,
 | 
			
		||||
    field: DBField,
 | 
			
		||||
    customUpdateField?: (attrs: Partial<DBField>) => void
 | 
			
		||||
) => {
 | 
			
		||||
    const {
 | 
			
		||||
        databaseType,
 | 
			
		||||
        customTypes,
 | 
			
		||||
        updateField: chartDBUpdateField,
 | 
			
		||||
        removeField: chartDBRemoveField,
 | 
			
		||||
    } = useChartDB();
 | 
			
		||||
 | 
			
		||||
    // Local state for responsive UI
 | 
			
		||||
    const [localFieldName, setLocalFieldName] = useState(field.name);
 | 
			
		||||
    const [localNullable, setLocalNullable] = useState(field.nullable);
 | 
			
		||||
    const [localPrimaryKey, setLocalPrimaryKey] = useState(field.primaryKey);
 | 
			
		||||
 | 
			
		||||
    const lastFieldNameRef = useRef<string>(field.name);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (localFieldName === lastFieldNameRef.current) {
 | 
			
		||||
            lastFieldNameRef.current = field.name;
 | 
			
		||||
            setLocalFieldName(field.name);
 | 
			
		||||
        }
 | 
			
		||||
    }, [field.name, localFieldName]);
 | 
			
		||||
 | 
			
		||||
    // Update local state when field properties change externally
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        setLocalNullable(field.nullable);
 | 
			
		||||
        setLocalPrimaryKey(field.primaryKey);
 | 
			
		||||
    }, [field.nullable, field.primaryKey]);
 | 
			
		||||
 | 
			
		||||
    // Use custom updateField if provided, otherwise use the chartDB one
 | 
			
		||||
    const updateField = useMemo(
 | 
			
		||||
        () =>
 | 
			
		||||
            customUpdateField
 | 
			
		||||
                ? (
 | 
			
		||||
                      _tableId: string,
 | 
			
		||||
                      _fieldId: string,
 | 
			
		||||
                      attrs: Partial<DBField>
 | 
			
		||||
                  ) => customUpdateField(attrs)
 | 
			
		||||
                : chartDBUpdateField,
 | 
			
		||||
        [customUpdateField, chartDBUpdateField]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Calculate primary key fields for validation
 | 
			
		||||
    const primaryKeyFields = useMemo(() => {
 | 
			
		||||
        return table.fields.filter((f) => f.primaryKey);
 | 
			
		||||
    }, [table.fields]);
 | 
			
		||||
 | 
			
		||||
    const primaryKeyCount = useMemo(
 | 
			
		||||
        () => primaryKeyFields.length,
 | 
			
		||||
        [primaryKeyFields.length]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Generate data type options for select box
 | 
			
		||||
    const dataFieldOptions = useMemo(() => {
 | 
			
		||||
        const standardTypes: SelectBoxOption[] = sortedDataTypeMap[
 | 
			
		||||
            databaseType
 | 
			
		||||
        ].map((type) => {
 | 
			
		||||
            const regexPatterns = generateFieldRegexPatterns(
 | 
			
		||||
                type,
 | 
			
		||||
                databaseType
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                label: type.name,
 | 
			
		||||
                value: type.id,
 | 
			
		||||
                regex: regexPatterns.regex,
 | 
			
		||||
                extractRegex: regexPatterns.extractRegex,
 | 
			
		||||
                group: customTypes?.length ? 'Standard Types' : undefined,
 | 
			
		||||
            };
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (!customTypes?.length) {
 | 
			
		||||
            return standardTypes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Add custom types as options
 | 
			
		||||
        const customTypeOptions: SelectBoxOption[] = customTypes.map(
 | 
			
		||||
            (type) => ({
 | 
			
		||||
                label: type.name,
 | 
			
		||||
                value: type.name,
 | 
			
		||||
                description:
 | 
			
		||||
                    type.kind === 'enum' ? `${type.values?.join(' | ')}` : '',
 | 
			
		||||
                group: 'Custom Types',
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return [...standardTypes, ...customTypeOptions];
 | 
			
		||||
    }, [databaseType, customTypes]);
 | 
			
		||||
 | 
			
		||||
    // Handle data type change
 | 
			
		||||
    const handleDataTypeChange = useCallback<
 | 
			
		||||
        NonNullable<SelectBoxProps['onChange']>
 | 
			
		||||
    >(
 | 
			
		||||
        (value, regexMatches) => {
 | 
			
		||||
            const dataType = sortedDataTypeMap[databaseType].find(
 | 
			
		||||
                (v) => v.id === value
 | 
			
		||||
            ) ?? {
 | 
			
		||||
                id: value as string,
 | 
			
		||||
                name: value as string,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let characterMaximumLength: string | undefined = undefined;
 | 
			
		||||
            let precision: number | undefined = undefined;
 | 
			
		||||
            let scale: number | undefined = undefined;
 | 
			
		||||
            let isArray: boolean | undefined = undefined;
 | 
			
		||||
 | 
			
		||||
            if (regexMatches?.length) {
 | 
			
		||||
                // Check if the last captured group is the array indicator []
 | 
			
		||||
                const lastMatch = regexMatches[regexMatches.length - 1];
 | 
			
		||||
                const hasArrayIndicator = lastMatch === '[]';
 | 
			
		||||
 | 
			
		||||
                if (dataType?.fieldAttributes?.hasCharMaxLength) {
 | 
			
		||||
                    characterMaximumLength = regexMatches[1]?.toLowerCase();
 | 
			
		||||
                } else if (
 | 
			
		||||
                    dataType?.fieldAttributes?.precision &&
 | 
			
		||||
                    dataType?.fieldAttributes?.scale
 | 
			
		||||
                ) {
 | 
			
		||||
                    precision = parseInt(regexMatches[1]);
 | 
			
		||||
                    scale = regexMatches[2]
 | 
			
		||||
                        ? parseInt(regexMatches[2])
 | 
			
		||||
                        : undefined;
 | 
			
		||||
                } else if (dataType?.fieldAttributes?.precision) {
 | 
			
		||||
                    precision = parseInt(regexMatches[1]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Set isArray if the array indicator was found and the type supports arrays
 | 
			
		||||
                if (hasArrayIndicator) {
 | 
			
		||||
                    const typeId = value as string;
 | 
			
		||||
                    if (supportsArrayDataType(typeId, databaseType)) {
 | 
			
		||||
                        isArray = true;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Explicitly set to false/undefined if no array indicator
 | 
			
		||||
                    isArray = undefined;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if (
 | 
			
		||||
                    dataType?.fieldAttributes?.hasCharMaxLength &&
 | 
			
		||||
                    field.characterMaximumLength
 | 
			
		||||
                ) {
 | 
			
		||||
                    characterMaximumLength = field.characterMaximumLength;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (dataType?.fieldAttributes?.precision && field.precision) {
 | 
			
		||||
                    precision = field.precision;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (dataType?.fieldAttributes?.scale && field.scale) {
 | 
			
		||||
                    scale = field.scale;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const newTypeName = dataType?.name ?? (value as string);
 | 
			
		||||
            const typeRequiresNotNull = requiresNotNull(newTypeName);
 | 
			
		||||
            const shouldForceIncrement = autoIncrementAlwaysOn(newTypeName);
 | 
			
		||||
 | 
			
		||||
            updateField(table.id, field.id, {
 | 
			
		||||
                characterMaximumLength,
 | 
			
		||||
                precision,
 | 
			
		||||
                scale,
 | 
			
		||||
                isArray,
 | 
			
		||||
                ...(typeRequiresNotNull ? { nullable: false } : {}),
 | 
			
		||||
                increment: shouldForceIncrement ? true : undefined,
 | 
			
		||||
                default: undefined,
 | 
			
		||||
                type: dataTypeDataToDataType(
 | 
			
		||||
                    dataType ?? {
 | 
			
		||||
                        id: value as string,
 | 
			
		||||
                        name: value as string,
 | 
			
		||||
                    }
 | 
			
		||||
                ),
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        [
 | 
			
		||||
            updateField,
 | 
			
		||||
            databaseType,
 | 
			
		||||
            field.characterMaximumLength,
 | 
			
		||||
            field.precision,
 | 
			
		||||
            field.scale,
 | 
			
		||||
            field.id,
 | 
			
		||||
            table.id,
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Debounced update for field name
 | 
			
		||||
    const debouncedNameUpdate = useDebounce(
 | 
			
		||||
        useCallback(
 | 
			
		||||
            (value: string) => {
 | 
			
		||||
                if (value.trim() !== field.name) {
 | 
			
		||||
                    updateField(table.id, field.id, { name: value });
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            [updateField, table.id, field.id, field.name]
 | 
			
		||||
        ),
 | 
			
		||||
        300 // 300ms debounce for text input
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Debounced update for nullable toggle
 | 
			
		||||
    const debouncedNullableUpdate = useDebounce(
 | 
			
		||||
        useCallback(
 | 
			
		||||
            (value: boolean) => {
 | 
			
		||||
                const updates: Partial<DBField> = { nullable: value };
 | 
			
		||||
 | 
			
		||||
                // If setting to nullable, clear increment (auto-increment requires NOT NULL)
 | 
			
		||||
                if (value && field.increment) {
 | 
			
		||||
                    updates.increment = undefined;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                updateField(table.id, field.id, updates);
 | 
			
		||||
            },
 | 
			
		||||
            [updateField, table.id, field.id, field.increment]
 | 
			
		||||
        ),
 | 
			
		||||
        100 // 100ms debounce for toggle
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Debounced update for primary key toggle
 | 
			
		||||
    const debouncedPrimaryKeyUpdate = useDebounce(
 | 
			
		||||
        useCallback(
 | 
			
		||||
            (value: boolean, primaryKeyCount: number) => {
 | 
			
		||||
                if (value) {
 | 
			
		||||
                    // When setting as primary key
 | 
			
		||||
                    const updates: Partial<DBField> = {
 | 
			
		||||
                        primaryKey: true,
 | 
			
		||||
                    };
 | 
			
		||||
                    // Only auto-set unique if this will be the only primary key
 | 
			
		||||
                    if (primaryKeyCount === 0) {
 | 
			
		||||
                        updates.unique = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    updateField(table.id, field.id, updates);
 | 
			
		||||
                } else {
 | 
			
		||||
                    // When removing primary key
 | 
			
		||||
                    updateField(table.id, field.id, {
 | 
			
		||||
                        primaryKey: false,
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            [updateField, table.id, field.id]
 | 
			
		||||
        ),
 | 
			
		||||
        100 // 100ms debounce for toggle
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Handle primary key toggle with optimistic update
 | 
			
		||||
    const handlePrimaryKeyToggle = useCallback(
 | 
			
		||||
        (value: boolean) => {
 | 
			
		||||
            setLocalPrimaryKey(value);
 | 
			
		||||
            debouncedPrimaryKeyUpdate(value, primaryKeyCount);
 | 
			
		||||
        },
 | 
			
		||||
        [primaryKeyCount, debouncedPrimaryKeyUpdate]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Handle nullable toggle with optimistic update
 | 
			
		||||
    const handleNullableToggle = useCallback(
 | 
			
		||||
        (value: boolean) => {
 | 
			
		||||
            setLocalNullable(value);
 | 
			
		||||
            debouncedNullableUpdate(value);
 | 
			
		||||
        },
 | 
			
		||||
        [debouncedNullableUpdate]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Handle name change with optimistic update
 | 
			
		||||
    const handleNameChange = useCallback(
 | 
			
		||||
        (value: string) => {
 | 
			
		||||
            setLocalFieldName(value);
 | 
			
		||||
            debouncedNameUpdate(value);
 | 
			
		||||
        },
 | 
			
		||||
        [debouncedNameUpdate]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Utility function to generate field suffix for display
 | 
			
		||||
    const generateFieldSuffix = useCallback(
 | 
			
		||||
        (typeId?: string) => {
 | 
			
		||||
            return generateDBFieldSuffix(
 | 
			
		||||
                {
 | 
			
		||||
                    ...field,
 | 
			
		||||
                    isArray: field.isArray && typeId === field.type.id,
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    databaseType,
 | 
			
		||||
                    forceExtended: true,
 | 
			
		||||
                    typeId,
 | 
			
		||||
                }
 | 
			
		||||
            );
 | 
			
		||||
        },
 | 
			
		||||
        [field, databaseType]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const removeField = useCallback(() => {
 | 
			
		||||
        chartDBRemoveField(table.id, field.id);
 | 
			
		||||
    }, [chartDBRemoveField, table.id, field.id]);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        dataFieldOptions,
 | 
			
		||||
        handleDataTypeChange,
 | 
			
		||||
        handlePrimaryKeyToggle,
 | 
			
		||||
        handleNullableToggle,
 | 
			
		||||
        handleNameChange,
 | 
			
		||||
        generateFieldSuffix,
 | 
			
		||||
        primaryKeyCount,
 | 
			
		||||
        fieldName: localFieldName,
 | 
			
		||||
        nullable: localNullable,
 | 
			
		||||
        primaryKey: localPrimaryKey,
 | 
			
		||||
        removeField,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
@@ -1,42 +0,0 @@
 | 
			
		||||
import { useCallback, useState, useEffect } from 'react';
 | 
			
		||||
import { useChartDB } from './use-chartdb';
 | 
			
		||||
import { useDebounce } from './use-debounce-v2';
 | 
			
		||||
import type { DBTable } from '@/lib/domain';
 | 
			
		||||
 | 
			
		||||
// Hook for updating table properties with debouncing for performance
 | 
			
		||||
export const useUpdateTable = (table: DBTable) => {
 | 
			
		||||
    const { updateTable: chartDBUpdateTable } = useChartDB();
 | 
			
		||||
    const [localTableName, setLocalTableName] = useState(table.name);
 | 
			
		||||
 | 
			
		||||
    // Debounced update function
 | 
			
		||||
    const debouncedUpdate = useDebounce(
 | 
			
		||||
        useCallback(
 | 
			
		||||
            (value: string) => {
 | 
			
		||||
                if (value.trim() && value.trim() !== table.name) {
 | 
			
		||||
                    chartDBUpdateTable(table.id, { name: value.trim() });
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            [chartDBUpdateTable, table.id, table.name]
 | 
			
		||||
        ),
 | 
			
		||||
        1000 // 1000ms debounce
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Update local state immediately for responsive UI
 | 
			
		||||
    const handleTableNameChange = useCallback(
 | 
			
		||||
        (value: string) => {
 | 
			
		||||
            setLocalTableName(value);
 | 
			
		||||
            debouncedUpdate(value);
 | 
			
		||||
        },
 | 
			
		||||
        [debouncedUpdate]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Update local state when table name changes externally
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        setLocalTableName(table.name);
 | 
			
		||||
    }, [table.name]);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        tableName: localTableName,
 | 
			
		||||
        handleTableNameChange,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
@@ -23,25 +23,23 @@ import { bn, bnMetadata } from './locales/bn';
 | 
			
		||||
import { gu, guMetadata } from './locales/gu';
 | 
			
		||||
import { vi, viMetadata } from './locales/vi';
 | 
			
		||||
import { ar, arMetadata } from './locales/ar';
 | 
			
		||||
import { hr, hrMetadata } from './locales/hr';
 | 
			
		||||
 | 
			
		||||
export const languages: LanguageMetadata[] = [
 | 
			
		||||
    enMetadata,
 | 
			
		||||
    esMetadata,
 | 
			
		||||
    frMetadata,
 | 
			
		||||
    deMetadata,
 | 
			
		||||
    esMetadata,
 | 
			
		||||
    ukMetadata,
 | 
			
		||||
    ruMetadata,
 | 
			
		||||
    trMetadata,
 | 
			
		||||
    hrMetadata,
 | 
			
		||||
    pt_BRMetadata,
 | 
			
		||||
    hiMetadata,
 | 
			
		||||
    jaMetadata,
 | 
			
		||||
    ko_KRMetadata,
 | 
			
		||||
    pt_BRMetadata,
 | 
			
		||||
    ukMetadata,
 | 
			
		||||
    ruMetadata,
 | 
			
		||||
    zh_CNMetadata,
 | 
			
		||||
    zh_TWMetadata,
 | 
			
		||||
    neMetadata,
 | 
			
		||||
    mrMetadata,
 | 
			
		||||
    trMetadata,
 | 
			
		||||
    id_IDMetadata,
 | 
			
		||||
    teMetadata,
 | 
			
		||||
    bnMetadata,
 | 
			
		||||
@@ -72,7 +70,6 @@ const resources = {
 | 
			
		||||
    gu,
 | 
			
		||||
    vi,
 | 
			
		||||
    ar,
 | 
			
		||||
    hr,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
i18n.use(LanguageDetector)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const ar: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'جديد',
 | 
			
		||||
            browse: 'تصفح',
 | 
			
		||||
            tables: 'الجداول',
 | 
			
		||||
            refs: 'المراجع',
 | 
			
		||||
            dependencies: 'التبعيات',
 | 
			
		||||
            custom_types: 'الأنواع المخصصة',
 | 
			
		||||
            visuals: 'مرئيات',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'الإجراءات',
 | 
			
		||||
                new: 'جديد...',
 | 
			
		||||
                browse: 'تصفح...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'ملف',
 | 
			
		||||
                new: 'جديد',
 | 
			
		||||
                open: 'فتح',
 | 
			
		||||
                save: 'حفظ',
 | 
			
		||||
                import: 'استيراد قاعدة بيانات',
 | 
			
		||||
                export_sql: 'SQL تصدير',
 | 
			
		||||
                export_as: 'تصدير كـ',
 | 
			
		||||
                delete_diagram: 'حذف',
 | 
			
		||||
                delete_diagram: 'حذف الرسم البياني',
 | 
			
		||||
                exit: 'خروج',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'تحرير',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'إخفاء الشريط الجانبي',
 | 
			
		||||
                hide_cardinality: 'إخفاء الكاردينالية',
 | 
			
		||||
                show_cardinality: 'إظهار الكاردينالية',
 | 
			
		||||
                hide_field_attributes: 'إخفاء خصائص الحقل',
 | 
			
		||||
                show_field_attributes: 'إظهار خصائص الحقل',
 | 
			
		||||
                zoom_on_scroll: 'تكبير/تصغير عند التمرير',
 | 
			
		||||
                show_views: 'عروض قاعدة البيانات',
 | 
			
		||||
                theme: 'المظهر',
 | 
			
		||||
                show_dependencies: 'إظهار الاعتمادات',
 | 
			
		||||
                hide_dependencies: 'إخفاء الاعتمادات',
 | 
			
		||||
@@ -74,13 +63,22 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'ترتيب تلقائي للرسم البياني',
 | 
			
		||||
            title: 'إعادة ترتيب الرسم البياني',
 | 
			
		||||
            description:
 | 
			
		||||
                'هذا الإجراء سيقوم بإعادة ترتيب الجداول في المخطط بشكل تلقائي. هل تريد المتابعة؟',
 | 
			
		||||
            reorder: 'ترتيب تلقائي',
 | 
			
		||||
            reorder: 'إعادة ترتيب',
 | 
			
		||||
            cancel: 'إلغاء',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'مخططات متعددة',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{formattedSchemas}} :مخططات في هذا الرسم البياني. يتم حاليا عرض {{schemasCount}} هناك',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'لا شيء',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'فشل النسخ',
 | 
			
		||||
@@ -115,11 +113,14 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
        copied: '!تم النسخ',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: ':المخطط',
 | 
			
		||||
            filter_by_schema: 'تصفية حسب المخطط',
 | 
			
		||||
            search_schema: '...بحث في المخطط',
 | 
			
		||||
            no_schemas_found: '.لم يتم العثور على مخططات',
 | 
			
		||||
            view_all_options: '...عرض جميع الخيارات',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'الجداول',
 | 
			
		||||
                add_table: 'إضافة جدول',
 | 
			
		||||
                add_view: 'إضافة عرض',
 | 
			
		||||
                filter: 'تصفية',
 | 
			
		||||
                collapse: 'طي الكل',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -145,14 +146,11 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'خصائص الحقل',
 | 
			
		||||
                        unique: 'فريد',
 | 
			
		||||
                        auto_increment: 'زيادة تلقائية',
 | 
			
		||||
                        comments: 'تعليقات',
 | 
			
		||||
                        no_comments: 'لا يوجد تعليقات',
 | 
			
		||||
                        delete_field: 'حذف الحقل',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'الدقة',
 | 
			
		||||
                        scale: 'النطاق',
 | 
			
		||||
                        default_value: 'Default Value',
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                    },
 | 
			
		||||
@@ -160,7 +158,6 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
                        title: 'خصائص الفهرس',
 | 
			
		||||
                        name: 'الإسم',
 | 
			
		||||
                        unique: 'فريد',
 | 
			
		||||
                        index_type: 'نوع الفهرس',
 | 
			
		||||
                        delete_index: 'حذف الفهرس',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -177,15 +174,12 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
                    description: 'أنشئ جدولاً للبدء',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'المراجع',
 | 
			
		||||
                filter: 'تصفية',
 | 
			
		||||
                collapse: 'طي الكل',
 | 
			
		||||
                add_relationship: 'إضافة علاقة',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'العلاقات',
 | 
			
		||||
                dependencies: 'الاعتمادات',
 | 
			
		||||
                filter: 'تصفية',
 | 
			
		||||
                add_relationship: 'إضافة علاقة',
 | 
			
		||||
                collapse: 'طي الكل',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'العلاقة',
 | 
			
		||||
                    primary: 'الجدول الأساسي',
 | 
			
		||||
                    foreign: 'الجدول المرتبط',
 | 
			
		||||
                    cardinality: 'الكاردينالية',
 | 
			
		||||
@@ -195,8 +189,16 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'حذف',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'لا توجد علاقات',
 | 
			
		||||
                    description: 'إنشئ علاقة لربط الجداول',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'الاعتمادات',
 | 
			
		||||
                filter: 'تصفية',
 | 
			
		||||
                collapse: 'طي الكل',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'الاعتماد',
 | 
			
		||||
                    table: 'الجدول',
 | 
			
		||||
                    dependent_table: 'عرض الاعتمادات',
 | 
			
		||||
                    delete_dependency: 'حذف',
 | 
			
		||||
@@ -206,8 +208,8 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'لا توجد علاقات',
 | 
			
		||||
                    description: 'إنشاء علاقة للبدء',
 | 
			
		||||
                    title: 'لا توجد اعتمادات',
 | 
			
		||||
                    description: 'إنشاء اعتماد للبدء',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -232,33 +234,6 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'مرئيات',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'ملاحظات',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'تصفية',
 | 
			
		||||
                add_note: 'إضافة ملاحظة',
 | 
			
		||||
                no_results: 'لم يتم العثور على ملاحظات',
 | 
			
		||||
                clear: 'مسح التصفية',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'لا توجد ملاحظات',
 | 
			
		||||
                    description: 'أنشئ ملاحظة لإضافة تعليقات نصية على اللوحة',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'ملاحظة فارغة',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'إجراءات الملاحظة',
 | 
			
		||||
                        edit_content: 'تحرير المحتوى',
 | 
			
		||||
                        delete_note: 'حذف الملاحظة',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -275,16 +250,12 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'لم يتم تحديد قيم التعداد',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -298,13 +269,10 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
            show_all: 'عرض الكل',
 | 
			
		||||
            undo: 'تراجع',
 | 
			
		||||
            redo: 'إعادة',
 | 
			
		||||
            reorder_diagram: 'ترتيب تلقائي للرسم البياني',
 | 
			
		||||
            reorder_diagram: 'إعادة ترتيب الرسم البياني',
 | 
			
		||||
            highlight_overlapping_tables: 'تمييز الجداول المتداخلة',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        new_diagram_dialog: {
 | 
			
		||||
@@ -335,13 +303,13 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
            cancel: 'إلغاء',
 | 
			
		||||
            import_from_file: 'استيراد من ملف',
 | 
			
		||||
            back: 'رجوع',
 | 
			
		||||
            empty_diagram: 'قاعدة بيانات فارغة',
 | 
			
		||||
            empty_diagram: 'مخطط فارغ',
 | 
			
		||||
            continue: 'متابعة',
 | 
			
		||||
            import: 'استيراد',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'فتح قاعدة بيانات',
 | 
			
		||||
            title: 'فتح مخطط',
 | 
			
		||||
            description: 'اختر مخططًا لفتحه من القائمة ادناه',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'الإسم',
 | 
			
		||||
@@ -351,12 +319,6 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'إلغاء',
 | 
			
		||||
            open: 'فتح',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'فتح',
 | 
			
		||||
                duplicate: 'تكرار',
 | 
			
		||||
                delete: 'حذف',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -442,13 +404,6 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
            cancel: 'إلغاء',
 | 
			
		||||
            confirm: 'تغيير',
 | 
			
		||||
        },
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'إنشاء مخطط جديد',
 | 
			
		||||
            description:
 | 
			
		||||
                'لا توجد مخططات حتى الآن. قم بإنشاء أول مخطط لتنظيم جداولك.',
 | 
			
		||||
            create: 'إنشاء',
 | 
			
		||||
            cancel: 'إلغاء',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: '!ساعدنا على التحسن',
 | 
			
		||||
@@ -502,11 +457,9 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'جدول جديد',
 | 
			
		||||
            new_view: 'عرض جديد',
 | 
			
		||||
            new_relationship: 'علاقة جديدة',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'ملاحظة جديدة',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -525,8 +478,6 @@ export const ar: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'اللغة',
 | 
			
		||||
        },
 | 
			
		||||
        on: 'تشغيل',
 | 
			
		||||
        off: 'إيقاف',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const bn: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'নতুন',
 | 
			
		||||
            browse: 'ব্রাউজ',
 | 
			
		||||
            tables: 'টেবিল',
 | 
			
		||||
            refs: 'রেফস',
 | 
			
		||||
            dependencies: 'নির্ভরতা',
 | 
			
		||||
            custom_types: 'কাস্টম টাইপ',
 | 
			
		||||
            visuals: 'ভিজ্যুয়াল',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'কার্য',
 | 
			
		||||
                new: 'নতুন...',
 | 
			
		||||
                browse: 'ব্রাউজ করুন...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'ফাইল',
 | 
			
		||||
                new: 'নতুন',
 | 
			
		||||
                open: 'খুলুন',
 | 
			
		||||
                save: 'সংরক্ষণ করুন',
 | 
			
		||||
                import: 'ডাটাবেস আমদানি করুন',
 | 
			
		||||
                export_sql: 'SQL রপ্তানি করুন',
 | 
			
		||||
                export_as: 'রূপে রপ্তানি করুন',
 | 
			
		||||
                delete_diagram: 'মুছুন',
 | 
			
		||||
                delete_diagram: 'ডায়াগ্রাম মুছুন',
 | 
			
		||||
                exit: 'প্রস্থান করুন',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'সম্পাদনা',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'সাইডবার লুকান',
 | 
			
		||||
                hide_cardinality: 'কার্ডিনালিটি লুকান',
 | 
			
		||||
                show_cardinality: 'কার্ডিনালিটি দেখান',
 | 
			
		||||
                hide_field_attributes: 'ফিল্ড অ্যাট্রিবিউট লুকান',
 | 
			
		||||
                show_field_attributes: 'ফিল্ড অ্যাট্রিবিউট দেখান',
 | 
			
		||||
                zoom_on_scroll: 'স্ক্রলে জুম করুন',
 | 
			
		||||
                show_views: 'ডাটাবেস ভিউ',
 | 
			
		||||
                theme: 'থিম',
 | 
			
		||||
                show_dependencies: 'নির্ভরতাগুলি দেখান',
 | 
			
		||||
                hide_dependencies: 'নির্ভরতাগুলি লুকান',
 | 
			
		||||
@@ -75,13 +64,22 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'স্বয়ংক্রিয় ডায়াগ্রাম সাজান',
 | 
			
		||||
            title: 'ডায়াগ্রাম পুনর্বিন্যাস করুন',
 | 
			
		||||
            description:
 | 
			
		||||
                'এই কাজটি ডায়াগ্রামের সমস্ত টেবিল পুনর্বিন্যাস করবে। আপনি কি চালিয়ে যেতে চান?',
 | 
			
		||||
            reorder: 'স্বয়ংক্রিয় সাজান',
 | 
			
		||||
            reorder: 'পুনর্বিন্যাস করুন',
 | 
			
		||||
            cancel: 'বাতিল করুন',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'বহু স্কিমা',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} স্কিমা এই ডায়াগ্রামে রয়েছে। বর্তমানে প্রদর্শিত: {{formattedSchemas}}।',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'কিছুই না',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'কপি ব্যর্থ হয়েছে',
 | 
			
		||||
@@ -116,11 +114,14 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
        copied: 'অনুলিপি সম্পন্ন!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'স্কিমা:',
 | 
			
		||||
            filter_by_schema: 'স্কিমা দ্বারা ফিল্টার করুন',
 | 
			
		||||
            search_schema: 'স্কিমা খুঁজুন...',
 | 
			
		||||
            no_schemas_found: 'কোনো স্কিমা পাওয়া যায়নি।',
 | 
			
		||||
            view_all_options: 'সমস্ত বিকল্প দেখুন...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'টেবিল',
 | 
			
		||||
                add_table: 'টেবিল যোগ করুন',
 | 
			
		||||
                add_view: 'ভিউ যোগ করুন',
 | 
			
		||||
                filter: 'ফিল্টার',
 | 
			
		||||
                collapse: 'সব ভাঁজ করুন',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -146,7 +147,6 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'ফিল্ড কর্ম',
 | 
			
		||||
                        unique: 'অদ্বিতীয়',
 | 
			
		||||
                        auto_increment: 'স্বয়ংক্রিয় বৃদ্ধি',
 | 
			
		||||
                        comments: 'মন্তব্য',
 | 
			
		||||
                        no_comments: 'কোনো মন্তব্য নেই',
 | 
			
		||||
                        delete_field: 'ফিল্ড মুছুন',
 | 
			
		||||
@@ -155,14 +155,11 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'নির্ভুলতা',
 | 
			
		||||
                        scale: 'স্কেল',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'ইনডেক্স কর্ম',
 | 
			
		||||
                        name: 'নাম',
 | 
			
		||||
                        unique: 'অদ্বিতীয়',
 | 
			
		||||
                        index_type: 'ইনডেক্স ধরন',
 | 
			
		||||
                        delete_index: 'ইনডেক্স মুছুন',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -179,17 +176,14 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
                    description: 'শুরু করতে একটি টেবিল তৈরি করুন',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'রেফস',
 | 
			
		||||
                filter: 'ফিল্টার',
 | 
			
		||||
                collapse: 'সব ভাঁজ করুন',
 | 
			
		||||
                add_relationship: 'সম্পর্ক যোগ করুন',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'সম্পর্ক',
 | 
			
		||||
                dependencies: 'নির্ভরতাগুলি',
 | 
			
		||||
                filter: 'ফিল্টার',
 | 
			
		||||
                add_relationship: 'সম্পর্ক যোগ করুন',
 | 
			
		||||
                collapse: 'সব ভাঁজ করুন',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'সম্পর্ক',
 | 
			
		||||
                    primary: 'প্রাথমিক টেবিল',
 | 
			
		||||
                    foreign: 'রেফারেন্স করা টেবিল',
 | 
			
		||||
                    foreign: 'বিদেশি টেবিল',
 | 
			
		||||
                    cardinality: 'কার্ডিনালিটি',
 | 
			
		||||
                    delete_relationship: 'মুছুন',
 | 
			
		||||
                    relationship_actions: {
 | 
			
		||||
@@ -197,19 +191,27 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'মুছুন',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'কোনো সম্পর্ক নেই',
 | 
			
		||||
                    description: 'টেবিল সংযোগ করতে একটি সম্পর্ক তৈরি করুন',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'নির্ভরতাগুলি',
 | 
			
		||||
                filter: 'ফিল্টার',
 | 
			
		||||
                collapse: 'ভাঁজ করুন',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'নির্ভরতা',
 | 
			
		||||
                    table: 'টেবিল',
 | 
			
		||||
                    dependent_table: 'নির্ভরশীল ভিউ',
 | 
			
		||||
                    delete_dependency: 'মুছুন',
 | 
			
		||||
                    dependent_table: 'নির্ভরশীল টেবিল',
 | 
			
		||||
                    delete_dependency: 'নির্ভরতা মুছুন',
 | 
			
		||||
                    dependency_actions: {
 | 
			
		||||
                        title: 'কর্ম',
 | 
			
		||||
                        delete_dependency: 'মুছুন',
 | 
			
		||||
                        delete_dependency: 'নির্ভরতা মুছুন',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'কোনো সম্পর্ক নেই',
 | 
			
		||||
                    description: 'শুরু করতে একটি সম্পর্ক তৈরি করুন',
 | 
			
		||||
                    title: 'কোনো নির্ভরতাগুলি নেই',
 | 
			
		||||
                    description: 'এই অংশে কোনো নির্ভরতা উপলব্ধ নেই।',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -233,35 +235,6 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'ভিজ্যুয়াল',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'নোট',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'ফিল্টার',
 | 
			
		||||
                add_note: 'নোট যোগ করুন',
 | 
			
		||||
                no_results: 'কোনো নোট পাওয়া যায়নি',
 | 
			
		||||
                clear: 'ফিল্টার সাফ করুন',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'কোনো নোট নেই',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'ক্যানভাসে টেক্সট টীকা যোগ করতে একটি নোট তৈরি করুন',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'খালি নোট',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'নোট ক্রিয়া',
 | 
			
		||||
                        edit_content: 'বিষয়বস্তু সম্পাদনা',
 | 
			
		||||
                        delete_note: 'নোট মুছুন',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -278,16 +251,12 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'কোন enum মান সংজ্ঞায়িত নেই',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -301,13 +270,9 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
            show_all: 'সব দেখান',
 | 
			
		||||
            undo: 'পূর্বাবস্থায় ফিরুন',
 | 
			
		||||
            redo: 'পুনরায় করুন',
 | 
			
		||||
            reorder_diagram: 'স্বয়ংক্রিয় ডায়াগ্রাম সাজান',
 | 
			
		||||
            reorder_diagram: 'ডায়াগ্রাম পুনর্বিন্যাস করুন',
 | 
			
		||||
            highlight_overlapping_tables: 'ওভারল্যাপিং টেবিল হাইলাইট করুন',
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@@ -339,13 +304,13 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
            cancel: 'বাতিল করুন',
 | 
			
		||||
            back: 'ফিরে যান',
 | 
			
		||||
            import_from_file: 'ফাইল থেকে আমদানি করুন',
 | 
			
		||||
            empty_diagram: 'খালি ডাটাবেস',
 | 
			
		||||
            empty_diagram: 'ফাঁকা চিত্র',
 | 
			
		||||
            continue: 'চালিয়ে যান',
 | 
			
		||||
            import: 'আমদানি করুন',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'ডেটাবেস খুলুন',
 | 
			
		||||
            title: 'চিত্র খুলুন',
 | 
			
		||||
            description: 'নিচের তালিকা থেকে একটি চিত্র নির্বাচন করুন।',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'নাম',
 | 
			
		||||
@@ -355,12 +320,6 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'বাতিল করুন',
 | 
			
		||||
            open: 'খুলুন',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'খুলুন',
 | 
			
		||||
                duplicate: 'ডুপ্লিকেট',
 | 
			
		||||
                delete: 'মুছুন',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -446,13 +405,6 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
            cancel: 'বাতিল করুন',
 | 
			
		||||
            confirm: 'পরিবর্তন করুন',
 | 
			
		||||
        },
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'নতুন স্কিমা তৈরি করুন',
 | 
			
		||||
            description:
 | 
			
		||||
                'এখনও কোনো স্কিমা নেই। আপনার টেবিলগুলি সংগঠিত করতে আপনার প্রথম স্কিমা তৈরি করুন।',
 | 
			
		||||
            create: 'তৈরি করুন',
 | 
			
		||||
            cancel: 'বাতিল করুন',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'আমাদের উন্নত করতে সাহায্য করুন!',
 | 
			
		||||
@@ -509,11 +461,9 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'নতুন টেবিল',
 | 
			
		||||
            new_view: 'নতুন ভিউ',
 | 
			
		||||
            new_relationship: 'নতুন সম্পর্ক',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'নতুন নোট',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -532,9 +482,6 @@ export const bn: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'ভাষা পরিবর্তন করুন',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'চালু',
 | 
			
		||||
        off: 'বন্ধ',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const de: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Neu',
 | 
			
		||||
            browse: 'Durchsuchen',
 | 
			
		||||
            tables: 'Tabellen',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Abhängigkeiten',
 | 
			
		||||
            custom_types: 'Benutzerdefinierte Typen',
 | 
			
		||||
            visuals: 'Darstellungen',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Aktionen',
 | 
			
		||||
                new: 'Neu...',
 | 
			
		||||
                browse: 'Durchsuchen...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Datei',
 | 
			
		||||
                new: 'Neu',
 | 
			
		||||
                open: 'Öffnen',
 | 
			
		||||
                save: 'Speichern',
 | 
			
		||||
                import: 'Datenbank importieren',
 | 
			
		||||
                export_sql: 'SQL exportieren',
 | 
			
		||||
                export_as: 'Exportieren als',
 | 
			
		||||
                delete_diagram: 'Löschen',
 | 
			
		||||
                delete_diagram: 'Diagramm löschen',
 | 
			
		||||
                exit: 'Beenden',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Bearbeiten',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const de: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'Seitenleiste ausblenden',
 | 
			
		||||
                hide_cardinality: 'Kardinalität ausblenden',
 | 
			
		||||
                show_cardinality: 'Kardinalität anzeigen',
 | 
			
		||||
                hide_field_attributes: 'Feldattribute ausblenden',
 | 
			
		||||
                show_field_attributes: 'Feldattribute anzeigen',
 | 
			
		||||
                zoom_on_scroll: 'Zoom beim Scrollen',
 | 
			
		||||
                show_views: 'Datenbankansichten',
 | 
			
		||||
                theme: 'Stil',
 | 
			
		||||
                show_dependencies: 'Abhängigkeiten anzeigen',
 | 
			
		||||
                hide_dependencies: 'Abhängigkeiten ausblenden',
 | 
			
		||||
@@ -75,13 +64,22 @@ export const de: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Diagramm automatisch anordnen',
 | 
			
		||||
            title: 'Diagramm neu anordnen',
 | 
			
		||||
            description:
 | 
			
		||||
                'Diese Aktion wird alle Tabellen im Diagramm neu anordnen. Möchten Sie fortfahren?',
 | 
			
		||||
            reorder: 'Automatisch anordnen',
 | 
			
		||||
            reorder: 'Neu anordnen',
 | 
			
		||||
            cancel: 'Abbrechen',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Mehrere Schemas',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} Schemas in diesem Diagramm. Derzeit angezeigt: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'Keine',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Kopieren fehlgeschlagen',
 | 
			
		||||
@@ -117,11 +115,14 @@ export const de: LanguageTranslation = {
 | 
			
		||||
        copied: 'Kopiert!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Schema:',
 | 
			
		||||
            filter_by_schema: 'Nach Schema filtern',
 | 
			
		||||
            search_schema: 'Schema suchen...',
 | 
			
		||||
            no_schemas_found: 'Keine Schemas gefunden.',
 | 
			
		||||
            view_all_options: 'Alle Optionen anzeigen...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Tabellen',
 | 
			
		||||
                add_table: 'Tabelle hinzufügen',
 | 
			
		||||
                add_view: 'Ansicht hinzufügen',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                collapse: 'Alle einklappen',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -147,7 +148,6 @@ export const de: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Feldattribute',
 | 
			
		||||
                        unique: 'Eindeutig',
 | 
			
		||||
                        auto_increment: 'Automatisch hochzählen',
 | 
			
		||||
                        comments: 'Kommentare',
 | 
			
		||||
                        no_comments: 'Keine Kommentare',
 | 
			
		||||
                        delete_field: 'Feld löschen',
 | 
			
		||||
@@ -156,14 +156,11 @@ export const de: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Präzision',
 | 
			
		||||
                        scale: 'Skalierung',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'Indexattribute',
 | 
			
		||||
                        name: 'Name',
 | 
			
		||||
                        unique: 'Eindeutig',
 | 
			
		||||
                        index_type: 'Indextyp',
 | 
			
		||||
                        delete_index: 'Index löschen',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -180,26 +177,32 @@ export const de: LanguageTranslation = {
 | 
			
		||||
                    description: 'Erstellen Sie eine Tabelle, um zu beginnen',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                collapse: 'Alle einklappen',
 | 
			
		||||
                add_relationship: 'Beziehung hinzufügen',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Beziehungen',
 | 
			
		||||
                dependencies: 'Abhängigkeiten',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                add_relationship: 'Beziehung hinzufügen',
 | 
			
		||||
                collapse: 'Alle einklappen',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Beziehung',
 | 
			
		||||
                    primary: 'Primäre Tabelle',
 | 
			
		||||
                    foreign: 'Referenzierte Tabelle',
 | 
			
		||||
                    cardinality: 'Kardinalität',
 | 
			
		||||
                    delete_relationship: 'Löschen',
 | 
			
		||||
                    delete_relationship: 'Beziehung löschen',
 | 
			
		||||
                    relationship_actions: {
 | 
			
		||||
                        title: 'Aktionen',
 | 
			
		||||
                        delete_relationship: 'Löschen',
 | 
			
		||||
                        delete_relationship: 'Beziehung löschen',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Keine Beziehungen',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Erstellen Sie eine Beziehung, um Tabellen zu verbinden',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Abhängigkeiten',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                collapse: 'Alle einklappen',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Abhängigkeit',
 | 
			
		||||
                    table: 'Tabelle',
 | 
			
		||||
                    dependent_table: 'Abhängige Ansicht',
 | 
			
		||||
                    delete_dependency: 'Löschen',
 | 
			
		||||
@@ -209,8 +212,8 @@ export const de: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Keine Beziehungen',
 | 
			
		||||
                    description: 'Erstellen Sie eine Beziehung, um zu beginnen',
 | 
			
		||||
                    title: 'Keine Abhängigkeiten',
 | 
			
		||||
                    description: 'Erstellen Sie eine Ansicht, um zu beginnen',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -234,35 +237,6 @@ export const de: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Darstellungen',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Notizen',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                add_note: 'Notiz hinzufügen',
 | 
			
		||||
                no_results: 'Keine Notizen gefunden',
 | 
			
		||||
                clear: 'Filter löschen',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Keine Notizen',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Erstellen Sie eine Notiz, um Textanmerkungen auf der Leinwand hinzuzufügen',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Leere Notiz',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Notiz-Aktionen',
 | 
			
		||||
                        edit_content: 'Inhalt bearbeiten',
 | 
			
		||||
                        delete_note: 'Notiz löschen',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -279,16 +253,12 @@ export const de: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'Keine Enum-Werte definiert',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -302,12 +272,7 @@ export const de: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Alle anzeigen',
 | 
			
		||||
            undo: 'Rückgängig',
 | 
			
		||||
            redo: 'Wiederholen',
 | 
			
		||||
            reorder_diagram: 'Diagramm automatisch anordnen',
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Diagramm neu anordnen',
 | 
			
		||||
            highlight_overlapping_tables: 'Überlappende Tabellen hervorheben',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -342,13 +307,13 @@ export const de: LanguageTranslation = {
 | 
			
		||||
            back: 'Zurück',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            empty_diagram: 'Leere Datenbank',
 | 
			
		||||
            empty_diagram: 'Leeres Diagramm',
 | 
			
		||||
            continue: 'Weiter',
 | 
			
		||||
            import: 'Importieren',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Datenbank öffnen',
 | 
			
		||||
            title: 'Diagramm öffnen',
 | 
			
		||||
            description: 'Wählen Sie ein Diagramm aus der Liste unten aus.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'Name',
 | 
			
		||||
@@ -358,12 +323,6 @@ export const de: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Abbrechen',
 | 
			
		||||
            open: 'Öffnen',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Öffnen',
 | 
			
		||||
                duplicate: 'Duplizieren',
 | 
			
		||||
                delete: 'Löschen',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -449,13 +408,6 @@ export const de: LanguageTranslation = {
 | 
			
		||||
            cancel: 'Abbrechen',
 | 
			
		||||
            confirm: 'Ändern',
 | 
			
		||||
        },
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Neues Schema erstellen',
 | 
			
		||||
            description:
 | 
			
		||||
                'Es existieren noch keine Schemas. Erstellen Sie Ihr erstes Schema, um Ihre Tabellen zu organisieren.',
 | 
			
		||||
            create: 'Erstellen',
 | 
			
		||||
            cancel: 'Abbrechen',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Hilf uns, uns zu verbessern!',
 | 
			
		||||
@@ -512,11 +464,9 @@ export const de: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Neue Tabelle',
 | 
			
		||||
            new_view: 'Neue Ansicht',
 | 
			
		||||
            new_relationship: 'Neue Beziehung',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'Neue Notiz',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -536,9 +486,6 @@ export const de: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Sprache',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Ein',
 | 
			
		||||
        off: 'Aus',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata } from '../types';
 | 
			
		||||
 | 
			
		||||
export const en = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'New',
 | 
			
		||||
            browse: 'Browse',
 | 
			
		||||
            tables: 'Tables',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Dependencies',
 | 
			
		||||
            custom_types: 'Custom Types',
 | 
			
		||||
            visuals: 'Visuals',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Actions',
 | 
			
		||||
                new: 'New...',
 | 
			
		||||
                browse: 'Browse...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'File',
 | 
			
		||||
                new: 'New',
 | 
			
		||||
                open: 'Open',
 | 
			
		||||
                save: 'Save',
 | 
			
		||||
                import: 'Import',
 | 
			
		||||
                export_sql: 'Export SQL',
 | 
			
		||||
                export_as: 'Export as',
 | 
			
		||||
                delete_diagram: 'Delete',
 | 
			
		||||
                delete_diagram: 'Delete Diagram',
 | 
			
		||||
                exit: 'Exit',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Edit',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const en = {
 | 
			
		||||
                hide_sidebar: 'Hide Sidebar',
 | 
			
		||||
                hide_cardinality: 'Hide Cardinality',
 | 
			
		||||
                show_cardinality: 'Show Cardinality',
 | 
			
		||||
                hide_field_attributes: 'Hide Field Attributes',
 | 
			
		||||
                show_field_attributes: 'Show Field Attributes',
 | 
			
		||||
                zoom_on_scroll: 'Zoom on Scroll',
 | 
			
		||||
                show_views: 'Database Views',
 | 
			
		||||
                theme: 'Theme',
 | 
			
		||||
                show_dependencies: 'Show Dependencies',
 | 
			
		||||
                hide_dependencies: 'Hide Dependencies',
 | 
			
		||||
@@ -73,13 +62,21 @@ export const en = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Auto Arrange Diagram',
 | 
			
		||||
            title: 'Reorder Diagram',
 | 
			
		||||
            description:
 | 
			
		||||
                'This action will rearrange all tables in the diagram. Do you want to continue?',
 | 
			
		||||
            reorder: 'Auto Arrange',
 | 
			
		||||
            reorder: 'Reorder',
 | 
			
		||||
            cancel: 'Cancel',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Multiple Schemas',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} schemas in this diagram. Currently displaying: {{formattedSchemas}}.',
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'none',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Copy failed',
 | 
			
		||||
@@ -114,11 +111,14 @@ export const en = {
 | 
			
		||||
        copied: 'Copied!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Schema:',
 | 
			
		||||
            filter_by_schema: 'Filter by schema',
 | 
			
		||||
            search_schema: 'Search schema...',
 | 
			
		||||
            no_schemas_found: 'No schemas found.',
 | 
			
		||||
            view_all_options: 'View all Options...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Tables',
 | 
			
		||||
                add_table: 'Add Table',
 | 
			
		||||
                add_view: 'Add View',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                collapse: 'Collapse All',
 | 
			
		||||
                clear: 'Clear Filter',
 | 
			
		||||
@@ -142,10 +142,7 @@ export const en = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Field Attributes',
 | 
			
		||||
                        unique: 'Unique',
 | 
			
		||||
                        auto_increment: 'Auto Increment',
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Precision',
 | 
			
		||||
                        scale: 'Scale',
 | 
			
		||||
                        comments: 'Comments',
 | 
			
		||||
                        no_comments: 'No comments',
 | 
			
		||||
                        default_value: 'Default Value',
 | 
			
		||||
@@ -156,7 +153,6 @@ export const en = {
 | 
			
		||||
                        title: 'Index Attributes',
 | 
			
		||||
                        name: 'Name',
 | 
			
		||||
                        unique: 'Unique',
 | 
			
		||||
                        index_type: 'Index Type',
 | 
			
		||||
                        delete_index: 'Delete Index',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -173,15 +169,12 @@ export const en = {
 | 
			
		||||
                    description: 'Create a table to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                collapse: 'Collapse All',
 | 
			
		||||
                add_relationship: 'Add Relationship',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Relationships',
 | 
			
		||||
                dependencies: 'Dependencies',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                add_relationship: 'Add Relationship',
 | 
			
		||||
                collapse: 'Collapse All',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Relationship',
 | 
			
		||||
                    primary: 'Primary Table',
 | 
			
		||||
                    foreign: 'Referenced Table',
 | 
			
		||||
                    cardinality: 'Cardinality',
 | 
			
		||||
@@ -191,8 +184,16 @@ export const en = {
 | 
			
		||||
                        delete_relationship: 'Delete',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'No relationships',
 | 
			
		||||
                    description: 'Create a relationship to connect tables',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Dependencies',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                collapse: 'Collapse All',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Dependency',
 | 
			
		||||
                    table: 'Table',
 | 
			
		||||
                    dependent_table: 'Dependent View',
 | 
			
		||||
                    delete_dependency: 'Delete',
 | 
			
		||||
@@ -202,8 +203,8 @@ export const en = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'No relationships',
 | 
			
		||||
                    description: 'Create a relationship to get started',
 | 
			
		||||
                    title: 'No dependencies',
 | 
			
		||||
                    description: 'Create a view to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -227,34 +228,6 @@ export const en = {
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuals',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Notes',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                add_note: 'Add Note',
 | 
			
		||||
                no_results: 'No notes found',
 | 
			
		||||
                clear: 'Clear Filter',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'No Notes',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Create a note to add text annotations on the canvas',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Empty note',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Note Actions',
 | 
			
		||||
                        edit_content: 'Edit Content',
 | 
			
		||||
                        delete_note: 'Delete Note',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
@@ -270,15 +243,11 @@ export const en = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'No enum values defined',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
@@ -293,11 +262,8 @@ export const en = {
 | 
			
		||||
            show_all: 'Show All',
 | 
			
		||||
            undo: 'Undo',
 | 
			
		||||
            redo: 'Redo',
 | 
			
		||||
            reorder_diagram: 'Auto Arrange Diagram',
 | 
			
		||||
            reorder_diagram: 'Reorder Diagram',
 | 
			
		||||
            highlight_overlapping_tables: 'Highlight Overlapping Tables',
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@@ -329,13 +295,13 @@ export const en = {
 | 
			
		||||
            cancel: 'Cancel',
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            back: 'Back',
 | 
			
		||||
            empty_diagram: 'Empty database',
 | 
			
		||||
            empty_diagram: 'Empty diagram',
 | 
			
		||||
            continue: 'Continue',
 | 
			
		||||
            import: 'Import',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Open Database',
 | 
			
		||||
            title: 'Open Diagram',
 | 
			
		||||
            description: 'Select a diagram to open from the list below.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'Name',
 | 
			
		||||
@@ -345,12 +311,6 @@ export const en = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Cancel',
 | 
			
		||||
            open: 'Open',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Open',
 | 
			
		||||
                duplicate: 'Duplicate',
 | 
			
		||||
                delete: 'Delete',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -436,14 +396,6 @@ export const en = {
 | 
			
		||||
            confirm: 'Change',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Create New Schema',
 | 
			
		||||
            description:
 | 
			
		||||
                'No schemas exist yet. Create your first schema to organize your tables.',
 | 
			
		||||
            create: 'Create',
 | 
			
		||||
            cancel: 'Cancel',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Help us improve!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -498,10 +450,8 @@ export const en = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'New Table',
 | 
			
		||||
            new_view: 'New View',
 | 
			
		||||
            new_relationship: 'New Relationship',
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'New Note',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -520,9 +470,6 @@ export const en = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Language',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'On',
 | 
			
		||||
        off: 'Off',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const es: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Nuevo',
 | 
			
		||||
            browse: 'Examinar',
 | 
			
		||||
            tables: 'Tablas',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Dependencias',
 | 
			
		||||
            custom_types: 'Tipos Personalizados',
 | 
			
		||||
            visuals: 'Visuales',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Acciones',
 | 
			
		||||
                new: 'Nuevo...',
 | 
			
		||||
                browse: 'Examinar...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Archivo',
 | 
			
		||||
                new: 'Nuevo',
 | 
			
		||||
                open: 'Abrir',
 | 
			
		||||
                save: 'Guardar',
 | 
			
		||||
                import: 'Importar Base de Datos',
 | 
			
		||||
                export_sql: 'Exportar SQL',
 | 
			
		||||
                export_as: 'Exportar como',
 | 
			
		||||
                delete_diagram: 'Eliminar',
 | 
			
		||||
                delete_diagram: 'Eliminar Diagrama',
 | 
			
		||||
                exit: 'Salir',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Editar',
 | 
			
		||||
@@ -32,12 +24,9 @@ export const es: LanguageTranslation = {
 | 
			
		||||
                view: 'Ver',
 | 
			
		||||
                hide_cardinality: 'Ocultar Cardinalidad',
 | 
			
		||||
                show_cardinality: 'Mostrar Cardinalidad',
 | 
			
		||||
                show_field_attributes: 'Mostrar Atributos de Campo',
 | 
			
		||||
                hide_field_attributes: 'Ocultar Atributos de Campo',
 | 
			
		||||
                show_sidebar: 'Mostrar Barra Lateral',
 | 
			
		||||
                hide_sidebar: 'Ocultar Barra Lateral',
 | 
			
		||||
                zoom_on_scroll: 'Zoom al Desplazarse',
 | 
			
		||||
                show_views: 'Vistas de Base de Datos',
 | 
			
		||||
                theme: 'Tema',
 | 
			
		||||
                show_dependencies: 'Mostrar dependencias',
 | 
			
		||||
                hide_dependencies: 'Ocultar dependencias',
 | 
			
		||||
@@ -74,10 +63,10 @@ export const es: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Organizar Diagrama Automáticamente',
 | 
			
		||||
            title: 'Reordenar Diagrama',
 | 
			
		||||
            description:
 | 
			
		||||
                'Esta acción reorganizará todas las tablas en el diagrama. ¿Deseas continuar?',
 | 
			
		||||
            reorder: 'Organizar Automáticamente',
 | 
			
		||||
            reorder: 'Reordenar',
 | 
			
		||||
            cancel: 'Cancelar',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@@ -115,11 +104,14 @@ export const es: LanguageTranslation = {
 | 
			
		||||
        copied: 'Copied!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Esquema:',
 | 
			
		||||
            filter_by_schema: 'Filtrar por esquema',
 | 
			
		||||
            search_schema: 'Buscar esquema...',
 | 
			
		||||
            no_schemas_found: 'No se encontraron esquemas.',
 | 
			
		||||
            view_all_options: 'Ver todas las opciones...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Tablas',
 | 
			
		||||
                add_table: 'Agregar Tabla',
 | 
			
		||||
                add_view: 'Agregar Vista',
 | 
			
		||||
                filter: 'Filtrar',
 | 
			
		||||
                collapse: 'Colapsar Todo',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -145,7 +137,6 @@ export const es: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Atributos del Campo',
 | 
			
		||||
                        unique: 'Único',
 | 
			
		||||
                        auto_increment: 'Autoincremento',
 | 
			
		||||
                        comments: 'Comentarios',
 | 
			
		||||
                        no_comments: 'Sin comentarios',
 | 
			
		||||
                        delete_field: 'Eliminar Campo',
 | 
			
		||||
@@ -154,14 +145,11 @@ export const es: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Precisión',
 | 
			
		||||
                        scale: 'Escala',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'Atributos del Índice',
 | 
			
		||||
                        name: 'Nombre',
 | 
			
		||||
                        unique: 'Único',
 | 
			
		||||
                        index_type: 'Tipo de Índice',
 | 
			
		||||
                        delete_index: 'Eliminar Índice',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -178,17 +166,14 @@ export const es: LanguageTranslation = {
 | 
			
		||||
                    description: 'Crea una tabla para comenzar',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Relaciones',
 | 
			
		||||
                add_relationship: 'Agregar Relación',
 | 
			
		||||
                filter: 'Filtrar',
 | 
			
		||||
                collapse: 'Colapsar Todo',
 | 
			
		||||
                add_relationship: 'Agregar Relación',
 | 
			
		||||
                relationships: 'Relaciones',
 | 
			
		||||
                dependencies: 'Dependencias',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Relación',
 | 
			
		||||
                    primary: 'Tabla Primaria',
 | 
			
		||||
                    foreign: 'Tabla Referenciada',
 | 
			
		||||
                    primary: 'Primaria',
 | 
			
		||||
                    foreign: 'Foránea',
 | 
			
		||||
                    cardinality: 'Cardinalidad',
 | 
			
		||||
                    delete_relationship: 'Eliminar',
 | 
			
		||||
                    relationship_actions: {
 | 
			
		||||
@@ -196,10 +181,18 @@ export const es: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'Eliminar',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'No hay relaciones',
 | 
			
		||||
                    description: 'Crea una relación para conectar tablas',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Dependencias',
 | 
			
		||||
                filter: 'Filtro',
 | 
			
		||||
                collapse: 'Colapsar todo',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Dependencia',
 | 
			
		||||
                    table: 'Tabla',
 | 
			
		||||
                    dependent_table: 'Vista Dependiente',
 | 
			
		||||
                    dependent_table: 'Vista dependiente',
 | 
			
		||||
                    delete_dependency: 'Eliminar',
 | 
			
		||||
                    dependency_actions: {
 | 
			
		||||
                        title: 'Acciones',
 | 
			
		||||
@@ -207,8 +200,8 @@ export const es: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Sin relaciones',
 | 
			
		||||
                    description: 'Crea una relación para comenzar',
 | 
			
		||||
                    title: 'Sin dependencias',
 | 
			
		||||
                    description: 'Crea una vista para comenzar',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -232,35 +225,6 @@ export const es: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuales',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Notas',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Filtrar',
 | 
			
		||||
                add_note: 'Agregar Nota',
 | 
			
		||||
                no_results: 'No se encontraron notas',
 | 
			
		||||
                clear: 'Limpiar Filtro',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Sin Notas',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Crea una nota para agregar anotaciones de texto en el lienzo',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Nota vacía',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Acciones de Nota',
 | 
			
		||||
                        edit_content: 'Editar Contenido',
 | 
			
		||||
                        delete_note: 'Eliminar Nota',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -277,16 +241,12 @@ export const es: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'No hay valores de enum definidos',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -300,11 +260,7 @@ export const es: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Mostrar Todo',
 | 
			
		||||
            undo: 'Deshacer',
 | 
			
		||||
            redo: 'Rehacer',
 | 
			
		||||
            reorder_diagram: 'Organizar Diagrama Automáticamente',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Reordenar Diagrama',
 | 
			
		||||
            highlight_overlapping_tables: 'Resaltar tablas superpuestas',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -339,13 +295,13 @@ export const es: LanguageTranslation = {
 | 
			
		||||
            back: 'Atrás',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            empty_diagram: 'Base de datos vacía',
 | 
			
		||||
            empty_diagram: 'Diagrama vacío',
 | 
			
		||||
            continue: 'Continuar',
 | 
			
		||||
            import: 'Importar',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Abrir Base de Datos',
 | 
			
		||||
            title: 'Abrir Diagrama',
 | 
			
		||||
            description:
 | 
			
		||||
                'Selecciona un diagrama para abrir de la lista a continuación.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
@@ -356,12 +312,6 @@ export const es: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Cancelar',
 | 
			
		||||
            open: 'Abrir',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Abrir',
 | 
			
		||||
                duplicate: 'Duplicar',
 | 
			
		||||
                delete: 'Eliminar',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -447,13 +397,6 @@ export const es: LanguageTranslation = {
 | 
			
		||||
            cancel: 'Cancelar',
 | 
			
		||||
            confirm: 'Cambiar',
 | 
			
		||||
        },
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Crear Nuevo Esquema',
 | 
			
		||||
            description:
 | 
			
		||||
                'Aún no existen esquemas. Crea tu primer esquema para organizar tus tablas.',
 | 
			
		||||
            create: 'Crear',
 | 
			
		||||
            cancel: 'Cancelar',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: '¡Ayúdanos a mejorar!',
 | 
			
		||||
@@ -463,6 +406,14 @@ export const es: LanguageTranslation = {
 | 
			
		||||
            confirm: '¡Claro!',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Múltiples Esquemas',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} esquemas en este diagrama. Actualmente mostrando: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'nada',
 | 
			
		||||
        },
 | 
			
		||||
        // TODO: Translate
 | 
			
		||||
        export_diagram_dialog: {
 | 
			
		||||
            title: 'Export Diagram',
 | 
			
		||||
@@ -511,11 +462,9 @@ export const es: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Nueva Tabla',
 | 
			
		||||
            new_view: 'Nueva Vista',
 | 
			
		||||
            new_relationship: 'Nueva Relación',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'Nueva Nota',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -535,9 +484,6 @@ export const es: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Idioma',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Encendido',
 | 
			
		||||
        off: 'Apagado',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const fr: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Nouveau',
 | 
			
		||||
            browse: 'Parcourir',
 | 
			
		||||
            tables: 'Tables',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Dépendances',
 | 
			
		||||
            custom_types: 'Types Personnalisés',
 | 
			
		||||
            visuals: 'Visuels',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Actions',
 | 
			
		||||
                new: 'Nouveau...',
 | 
			
		||||
                browse: 'Parcourir...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Fichier',
 | 
			
		||||
                new: 'Nouveau',
 | 
			
		||||
                open: 'Ouvrir',
 | 
			
		||||
                save: 'Enregistrer',
 | 
			
		||||
                import: 'Importer Base de Données',
 | 
			
		||||
                export_sql: 'Exporter SQL',
 | 
			
		||||
                export_as: 'Exporter en tant que',
 | 
			
		||||
                delete_diagram: 'Supprimer',
 | 
			
		||||
                delete_diagram: 'Supprimer le Diagramme',
 | 
			
		||||
                exit: 'Quitter',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Édition',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'Cacher la Barre Latérale',
 | 
			
		||||
                hide_cardinality: 'Cacher la Cardinalité',
 | 
			
		||||
                show_cardinality: 'Afficher la Cardinalité',
 | 
			
		||||
                hide_field_attributes: 'Masquer les Attributs de Champ',
 | 
			
		||||
                show_field_attributes: 'Afficher les Attributs de Champ',
 | 
			
		||||
                zoom_on_scroll: 'Zoom sur le Défilement',
 | 
			
		||||
                show_views: 'Vues de Base de Données',
 | 
			
		||||
                theme: 'Thème',
 | 
			
		||||
                show_dependencies: 'Afficher les Dépendances',
 | 
			
		||||
                hide_dependencies: 'Masquer les Dépendances',
 | 
			
		||||
@@ -73,10 +62,10 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Organiser Automatiquement le Diagramme',
 | 
			
		||||
            title: 'Réorganiser le Diagramme',
 | 
			
		||||
            description:
 | 
			
		||||
                'Cette action réorganisera toutes les tables dans le diagramme. Voulez-vous continuer ?',
 | 
			
		||||
            reorder: 'Organiser Automatiquement',
 | 
			
		||||
            reorder: 'Réorganiser',
 | 
			
		||||
            cancel: 'Annuler',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@@ -114,11 +103,14 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
        copied: 'Copié !',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Schéma:',
 | 
			
		||||
            filter_by_schema: 'Filtrer par schéma',
 | 
			
		||||
            search_schema: 'Rechercher un schéma...',
 | 
			
		||||
            no_schemas_found: 'Aucun schéma trouvé.',
 | 
			
		||||
            view_all_options: 'Voir toutes les Options...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Tables',
 | 
			
		||||
                add_table: 'Ajouter une Table',
 | 
			
		||||
                add_view: 'Ajouter une Vue',
 | 
			
		||||
                filter: 'Filtrer',
 | 
			
		||||
                collapse: 'Réduire Tout',
 | 
			
		||||
                clear: 'Effacer le Filtre',
 | 
			
		||||
@@ -143,7 +135,6 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Attributs du Champ',
 | 
			
		||||
                        unique: 'Unique',
 | 
			
		||||
                        auto_increment: 'Auto-incrément',
 | 
			
		||||
                        comments: 'Commentaires',
 | 
			
		||||
                        no_comments: 'Pas de commentaires',
 | 
			
		||||
                        delete_field: 'Supprimer le Champ',
 | 
			
		||||
@@ -152,14 +143,11 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Précision',
 | 
			
		||||
                        scale: 'Échelle',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: "Attributs de l'Index",
 | 
			
		||||
                        name: 'Nom',
 | 
			
		||||
                        unique: 'Unique',
 | 
			
		||||
                        index_type: "Type d'index",
 | 
			
		||||
                        delete_index: "Supprimer l'Index",
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -176,15 +164,12 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
                    description: 'Créez une table pour commencer',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Filtrer',
 | 
			
		||||
                collapse: 'Réduire Tout',
 | 
			
		||||
                add_relationship: 'Ajouter une Relation',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Relations',
 | 
			
		||||
                dependencies: 'Dépendances',
 | 
			
		||||
                filter: 'Filtrer',
 | 
			
		||||
                add_relationship: 'Ajouter une Relation',
 | 
			
		||||
                collapse: 'Réduire Tout',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Relation',
 | 
			
		||||
                    primary: 'Table Principale',
 | 
			
		||||
                    foreign: 'Table Référencée',
 | 
			
		||||
                    cardinality: 'Cardinalité',
 | 
			
		||||
@@ -194,8 +179,16 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'Supprimer',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Aucune relation',
 | 
			
		||||
                    description: 'Créez une relation pour connecter les tables',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Dépendances',
 | 
			
		||||
                filter: 'Filtrer',
 | 
			
		||||
                collapse: 'Réduire Tout',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Dépendance',
 | 
			
		||||
                    table: 'Table',
 | 
			
		||||
                    dependent_table: 'Vue Dépendante',
 | 
			
		||||
                    delete_dependency: 'Supprimer',
 | 
			
		||||
@@ -205,8 +198,8 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Aucune relation',
 | 
			
		||||
                    description: 'Créez une relation pour commencer',
 | 
			
		||||
                    title: 'Aucune dépendance',
 | 
			
		||||
                    description: 'Créez une vue pour commencer',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -230,35 +223,6 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuels',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Notes',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Filtrer',
 | 
			
		||||
                add_note: 'Ajouter une Note',
 | 
			
		||||
                no_results: 'Aucune note trouvée',
 | 
			
		||||
                clear: 'Effacer le Filtre',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Pas de Notes',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Créez une note pour ajouter des annotations de texte sur le canevas',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Note vide',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Actions de Note',
 | 
			
		||||
                        edit_content: 'Modifier le Contenu',
 | 
			
		||||
                        delete_note: 'Supprimer la Note',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -275,16 +239,12 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: "Aucune valeur d'énumération définie",
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -298,11 +258,7 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Afficher Tout',
 | 
			
		||||
            undo: 'Annuler',
 | 
			
		||||
            redo: 'Rétablir',
 | 
			
		||||
            reorder_diagram: 'Organiser Automatiquement le Diagramme',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Réorganiser le Diagramme',
 | 
			
		||||
            highlight_overlapping_tables: 'Surligner les tables chevauchées',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -336,13 +292,13 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
            cancel: 'Annuler',
 | 
			
		||||
            back: 'Retour',
 | 
			
		||||
            import_from_file: "Importer à partir d'un fichier",
 | 
			
		||||
            empty_diagram: 'Base de données vide',
 | 
			
		||||
            empty_diagram: 'Diagramme vide',
 | 
			
		||||
            continue: 'Continuer',
 | 
			
		||||
            import: 'Importer',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Ouvrir Base de Données',
 | 
			
		||||
            title: 'Ouvrir Diagramme',
 | 
			
		||||
            description:
 | 
			
		||||
                'Sélectionnez un diagramme à ouvrir dans la liste ci-dessous.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
@@ -353,12 +309,6 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Annuler',
 | 
			
		||||
            open: 'Ouvrir',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Ouvrir',
 | 
			
		||||
                duplicate: 'Dupliquer',
 | 
			
		||||
                delete: 'Supprimer',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -396,6 +346,15 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
            transparent_description: 'Remove background color from image.',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Schémas Multiples',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} schémas dans ce diagramme. Actuellement affiché(s) : {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'Aucun',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        new_table_schema_dialog: {
 | 
			
		||||
            title: 'Sélectionner un Schéma',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -418,13 +377,6 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
            cancel: 'Annuler',
 | 
			
		||||
            confirm: 'Modifier',
 | 
			
		||||
        },
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Créer un Nouveau Schéma',
 | 
			
		||||
            description:
 | 
			
		||||
                "Aucun schéma n'existe encore. Créez votre premier schéma pour organiser vos tables.",
 | 
			
		||||
            create: 'Créer',
 | 
			
		||||
            cancel: 'Annuler',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_relationship_dialog: {
 | 
			
		||||
            title: 'Créer une Relation',
 | 
			
		||||
@@ -507,11 +459,9 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Nouvelle Table',
 | 
			
		||||
            new_view: 'Nouvelle Vue',
 | 
			
		||||
            new_relationship: 'Nouvelle Relation',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'Nouvelle Note',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -531,9 +481,6 @@ export const fr: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Langue',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Activé',
 | 
			
		||||
        off: 'Désactivé',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const gu: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'નવું',
 | 
			
		||||
            browse: 'બ્રાઉજ',
 | 
			
		||||
            tables: 'ટેબલો',
 | 
			
		||||
            refs: 'રેફ્સ',
 | 
			
		||||
            dependencies: 'નિર્ભરતાઓ',
 | 
			
		||||
            custom_types: 'કસ્ટમ ટાઇપ',
 | 
			
		||||
            visuals: 'Visuals',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'ક્રિયાઓ',
 | 
			
		||||
                new: 'નવું...',
 | 
			
		||||
                browse: 'બ્રાઉજ કરો...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'ફાઇલ',
 | 
			
		||||
                new: 'નવું',
 | 
			
		||||
                open: 'ખોલો',
 | 
			
		||||
                save: 'સાચવો',
 | 
			
		||||
                import: 'ડેટાબેસ આયાત કરો',
 | 
			
		||||
                export_sql: 'SQL નિકાસ કરો',
 | 
			
		||||
                export_as: 'રૂપે નિકાસ કરો',
 | 
			
		||||
                delete_diagram: 'કાઢી નાખો',
 | 
			
		||||
                delete_diagram: 'ડાયાગ્રામ કાઢી નાખો',
 | 
			
		||||
                exit: 'બહાર જાઓ',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'ફેરફાર',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'સાઇડબાર છુપાવો',
 | 
			
		||||
                hide_cardinality: 'કાર્ડિનાલિટી છુપાવો',
 | 
			
		||||
                show_cardinality: 'કાર્ડિનાલિટી બતાવો',
 | 
			
		||||
                hide_field_attributes: 'ફીલ્ડ અટ્રિબ્યુટ્સ છુપાવો',
 | 
			
		||||
                show_field_attributes: 'ફીલ્ડ અટ્રિબ્યુટ્સ બતાવો',
 | 
			
		||||
                zoom_on_scroll: 'સ્ક્રોલ પર ઝૂમ કરો',
 | 
			
		||||
                show_views: 'ડેટાબેઝ વ્યૂઝ',
 | 
			
		||||
                theme: 'થિમ',
 | 
			
		||||
                show_dependencies: 'નિર્ભરતાઓ બતાવો',
 | 
			
		||||
                hide_dependencies: 'નિર્ભરતાઓ છુપાવો',
 | 
			
		||||
@@ -75,13 +64,22 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'ડાયાગ્રામ ઑટોમેટિક ગોઠવો',
 | 
			
		||||
            title: 'ડાયાગ્રામ ફરી વ્યવસ્થિત કરો',
 | 
			
		||||
            description:
 | 
			
		||||
                'આ ક્રિયા ડાયાગ્રામમાં બધી ટેબલ્સને ફરીથી વ્યવસ્થિત કરશે. શું તમે ચાલુ રાખવા માંગો છો?',
 | 
			
		||||
            reorder: 'ઑટોમેટિક ગોઠવો',
 | 
			
		||||
            reorder: 'ફરી વ્યવસ્થિત કરો',
 | 
			
		||||
            cancel: 'રદ કરો',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'કઈંક વધારે સ્કીમા',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} સ્કીમા આ ડાયાગ્રામમાં છે. હાલમાં દર્શાવેલ છે: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'કઈ નહીં',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'નકલ નિષ્ફળ',
 | 
			
		||||
@@ -116,11 +114,14 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
        copied: 'નકલ થયું!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'સ્કીમા:',
 | 
			
		||||
            filter_by_schema: 'સ્કીમા દ્વારા ફિલ્ટર કરો',
 | 
			
		||||
            search_schema: 'સ્કીમા શોધો...',
 | 
			
		||||
            no_schemas_found: 'કોઈ સ્કીમા મળ્યા નથી.',
 | 
			
		||||
            view_all_options: 'બધા વિકલ્પો જુઓ...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'ટેબલ્સ',
 | 
			
		||||
                add_table: 'ટેબલ ઉમેરો',
 | 
			
		||||
                add_view: 'વ્યૂ ઉમેરો',
 | 
			
		||||
                filter: 'ફિલ્ટર',
 | 
			
		||||
                collapse: 'બધાને સકુચિત કરો',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -147,7 +148,6 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'ફીલ્ડ લક્ષણો',
 | 
			
		||||
                        unique: 'અદ્વિતીય',
 | 
			
		||||
                        auto_increment: 'ઑટો ઇન્ક્રિમેન્ટ',
 | 
			
		||||
                        comments: 'ટિપ્પણીઓ',
 | 
			
		||||
                        no_comments: 'કોઈ ટિપ્પણીઓ નથી',
 | 
			
		||||
                        delete_field: 'ફીલ્ડ કાઢી નાખો',
 | 
			
		||||
@@ -156,14 +156,11 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'ચોકસાઈ',
 | 
			
		||||
                        scale: 'માપ',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'ઇન્ડેક્સ લક્ષણો',
 | 
			
		||||
                        name: 'નામ',
 | 
			
		||||
                        unique: 'અદ્વિતીય',
 | 
			
		||||
                        index_type: 'ઇન્ડેક્સ પ્રકાર',
 | 
			
		||||
                        delete_index: 'ઇન્ડેક્સ કાઢી નાખો',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -180,17 +177,14 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
                    description: 'શરૂ કરવા માટે એક ટેબલ બનાવો',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'રેફ્સ',
 | 
			
		||||
                filter: 'ફિલ્ટર',
 | 
			
		||||
                collapse: 'બધાને સકુચિત કરો',
 | 
			
		||||
                add_relationship: 'સંબંધ ઉમેરો',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'સંબંધો',
 | 
			
		||||
                dependencies: 'નિર્ભરતાઓ',
 | 
			
		||||
                filter: 'ફિલ્ટર',
 | 
			
		||||
                add_relationship: 'સંબંધ ઉમેરો',
 | 
			
		||||
                collapse: 'બધાને સકુચિત કરો',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'સંબંધ',
 | 
			
		||||
                    primary: 'પ્રાથમિક ટેબલ',
 | 
			
		||||
                    foreign: 'સંદર્ભિત ટેબલ',
 | 
			
		||||
                    foreign: 'સંદર્ભ ટેબલ',
 | 
			
		||||
                    cardinality: 'કાર્ડિનાલિટી',
 | 
			
		||||
                    delete_relationship: 'કાઢી નાખો',
 | 
			
		||||
                    relationship_actions: {
 | 
			
		||||
@@ -198,19 +192,27 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'કાઢી નાખો',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'કોઈ સંબંધો નથી',
 | 
			
		||||
                    description: 'ટેબલ્સ કનેક્ટ કરવા માટે એક સંબંધ બનાવો',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'નિર્ભરતાઓ',
 | 
			
		||||
                filter: 'ફિલ્ટર',
 | 
			
		||||
                collapse: 'સિકોડો',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'નિર્ભરતા',
 | 
			
		||||
                    table: 'ટેબલ',
 | 
			
		||||
                    dependent_table: 'નિર્ભરશીલ વ્યૂ',
 | 
			
		||||
                    delete_dependency: 'કાઢી નાખો',
 | 
			
		||||
                    dependent_table: 'આધાર રાખેલું ટેબલ',
 | 
			
		||||
                    delete_dependency: 'નિર્ભરતા કાઢી નાખો',
 | 
			
		||||
                    dependency_actions: {
 | 
			
		||||
                        title: 'ક્રિયાઓ',
 | 
			
		||||
                        delete_dependency: 'કાઢી નાખો',
 | 
			
		||||
                        delete_dependency: 'નિર્ભરતા કાઢી નાખો',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'કોઈ સંબંધો નથી',
 | 
			
		||||
                    description: 'શરૂ કરવા માટે એક સંબંધ બનાવો',
 | 
			
		||||
                    title: 'કોઈ નિર્ભરતાઓ નથી',
 | 
			
		||||
                    description: 'આ વિભાગમાં કોઈ નિર્ભરતા ઉપલબ્ધ નથી.',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -234,35 +236,6 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuals',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'નોંધો',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'ફિલ્ટર',
 | 
			
		||||
                add_note: 'નોંધ ઉમેરો',
 | 
			
		||||
                no_results: 'કોઈ નોંધો મળી નથી',
 | 
			
		||||
                clear: 'ફિલ્ટર સાફ કરો',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'કોઈ નોંધો નથી',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'કેનવાસ પર ટેક્સ્ટ એનોટેશન ઉમેરવા માટે નોંધ બનાવો',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'ખાલી નોંધ',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'નોંધ ક્રિયાઓ',
 | 
			
		||||
                        edit_content: 'સામગ્રી સંપાદિત કરો',
 | 
			
		||||
                        delete_note: 'નોંધ કાઢી નાખો',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -279,16 +252,12 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'કોઈ enum મૂલ્યો વ્યાખ્યાયિત નથી',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -302,11 +271,7 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
            show_all: 'બધું બતાવો',
 | 
			
		||||
            undo: 'અનડુ',
 | 
			
		||||
            redo: 'રીડુ',
 | 
			
		||||
            reorder_diagram: 'ડાયાગ્રામ ઑટોમેટિક ગોઠવો',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'ડાયાગ્રામ ફરીથી વ્યવસ્થિત કરો',
 | 
			
		||||
            highlight_overlapping_tables: 'ઓવરલેપ કરતો ટેબલ હાઇલાઇટ કરો',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -339,13 +304,13 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
            cancel: 'રદ કરો',
 | 
			
		||||
            back: 'પાછા',
 | 
			
		||||
            import_from_file: 'ફાઇલમાંથી આયાત કરો',
 | 
			
		||||
            empty_diagram: 'ખાલી ડેટાબેસ',
 | 
			
		||||
            empty_diagram: 'ખાલી ડાયાગ્રામ',
 | 
			
		||||
            continue: 'ચાલુ રાખો',
 | 
			
		||||
            import: 'આયાત કરો',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'ડેટાબેસ ખોલો',
 | 
			
		||||
            title: 'ડાયાગ્રામ ખોલો',
 | 
			
		||||
            description: 'નીચેની યાદીમાંથી એક ડાયાગ્રામ પસંદ કરો.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'નામ',
 | 
			
		||||
@@ -355,12 +320,6 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'રદ કરો',
 | 
			
		||||
            open: 'ખોલો',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'ખોલો',
 | 
			
		||||
                duplicate: 'ડુપ્લિકેટ',
 | 
			
		||||
                delete: 'કાઢી નાખો',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -447,14 +406,6 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
            confirm: 'બદલો',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'નવું સ્કીમા બનાવો',
 | 
			
		||||
            description:
 | 
			
		||||
                'હજી સુધી કોઈ સ્કીમા અસ્તિત્વમાં નથી. તમારા ટેબલ્સ ને વ્યવસ્થિત કરવા માટે તમારું પહેલું સ્કીમા બનાવો.',
 | 
			
		||||
            create: 'બનાવો',
 | 
			
		||||
            cancel: 'રદ કરો',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'અમને સુધારવામાં મદદ કરો!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -510,11 +461,9 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'નવું ટેબલ',
 | 
			
		||||
            new_view: 'નવું વ્યૂ',
 | 
			
		||||
            new_relationship: 'નવો સંબંધ',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'નવી નોંધ',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -533,9 +482,6 @@ export const gu: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'ભાષા બદલો',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'ચાલુ',
 | 
			
		||||
        off: 'બંધ',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const hi: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'नया',
 | 
			
		||||
            browse: 'ब्राउज़',
 | 
			
		||||
            tables: 'टेबल',
 | 
			
		||||
            refs: 'रेफ्स',
 | 
			
		||||
            dependencies: 'निर्भरताएं',
 | 
			
		||||
            custom_types: 'कस्टम टाइप',
 | 
			
		||||
            visuals: 'Visuals',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'कार्य',
 | 
			
		||||
                new: 'नया...',
 | 
			
		||||
                browse: 'ब्राउज़ करें...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'फ़ाइल',
 | 
			
		||||
                new: 'नया',
 | 
			
		||||
                open: 'खोलें',
 | 
			
		||||
                save: 'सहेजें',
 | 
			
		||||
                import: 'डेटाबेस आयात करें',
 | 
			
		||||
                export_sql: 'SQL निर्यात करें',
 | 
			
		||||
                export_as: 'के रूप में निर्यात करें',
 | 
			
		||||
                delete_diagram: 'हटाएँ',
 | 
			
		||||
                delete_diagram: 'आरेख हटाएँ',
 | 
			
		||||
                exit: 'बाहर जाएँ',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'संपादित करें',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'साइडबार छिपाएँ',
 | 
			
		||||
                hide_cardinality: 'कार्डिनैलिटी छिपाएँ',
 | 
			
		||||
                show_cardinality: 'कार्डिनैलिटी दिखाएँ',
 | 
			
		||||
                hide_field_attributes: 'फ़ील्ड विशेषताएँ छिपाएँ',
 | 
			
		||||
                show_field_attributes: 'फ़ील्ड विशेषताएँ दिखाएँ',
 | 
			
		||||
                zoom_on_scroll: 'स्क्रॉल पर ज़ूम',
 | 
			
		||||
                show_views: 'डेटाबेस व्यू',
 | 
			
		||||
                theme: 'थीम',
 | 
			
		||||
                show_dependencies: 'निर्भरता दिखाएँ',
 | 
			
		||||
                hide_dependencies: 'निर्भरता छिपाएँ',
 | 
			
		||||
@@ -74,13 +63,22 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'आरेख स्वचालित व्यवस्थित करें',
 | 
			
		||||
            title: 'आरेख पुनः व्यवस्थित करें',
 | 
			
		||||
            description:
 | 
			
		||||
                'यह क्रिया आरेख में सभी तालिकाओं को पुनः व्यवस्थित कर देगी। क्या आप जारी रखना चाहते हैं?',
 | 
			
		||||
            reorder: 'स्वचालित व्यवस्थित करें',
 | 
			
		||||
            reorder: 'पुनः व्यवस्थित करें',
 | 
			
		||||
            cancel: 'रद्द करें',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'एकाधिक स्कीमा',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} स्कीमा इस आरेख में हैं। वर्तमान में प्रदर्शित: {{formattedSchemas}}।',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'कोई नहीं',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'कॉपी असफल',
 | 
			
		||||
@@ -116,11 +114,14 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
        copied: 'Copied!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'स्कीमा:',
 | 
			
		||||
            filter_by_schema: 'स्कीमा द्वारा फ़िल्टर करें',
 | 
			
		||||
            search_schema: 'स्कीमा खोजें...',
 | 
			
		||||
            no_schemas_found: 'कोई स्कीमा नहीं मिला।',
 | 
			
		||||
            view_all_options: 'सभी विकल्प देखें...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'तालिकाएँ',
 | 
			
		||||
                add_table: 'तालिका जोड़ें',
 | 
			
		||||
                add_view: 'व्यू जोड़ें',
 | 
			
		||||
                filter: 'फ़िल्टर',
 | 
			
		||||
                collapse: 'सभी को संक्षिप्त करें',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -146,7 +147,6 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'फ़ील्ड विशेषताएँ',
 | 
			
		||||
                        unique: 'अद्वितीय',
 | 
			
		||||
                        auto_increment: 'ऑटो इंक्रीमेंट',
 | 
			
		||||
                        comments: 'टिप्पणियाँ',
 | 
			
		||||
                        no_comments: 'कोई टिप्पणी नहीं',
 | 
			
		||||
                        delete_field: 'फ़ील्ड हटाएँ',
 | 
			
		||||
@@ -155,14 +155,11 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Precision',
 | 
			
		||||
                        scale: 'Scale',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'सूचकांक विशेषताएँ',
 | 
			
		||||
                        name: 'नाम',
 | 
			
		||||
                        unique: 'अद्वितीय',
 | 
			
		||||
                        index_type: 'इंडेक्स प्रकार',
 | 
			
		||||
                        delete_index: 'सूचकांक हटाएँ',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -179,15 +176,12 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
                    description: 'शुरू करने के लिए एक तालिका बनाएँ',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'रेफ्स',
 | 
			
		||||
                filter: 'फ़िल्टर',
 | 
			
		||||
                collapse: 'सभी को संक्षिप्त करें',
 | 
			
		||||
                add_relationship: 'संबंध जोड़ें',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'संबंध',
 | 
			
		||||
                dependencies: 'निर्भरताएँ',
 | 
			
		||||
                filter: 'फ़िल्टर',
 | 
			
		||||
                add_relationship: 'संबंध जोड़ें',
 | 
			
		||||
                collapse: 'सभी को संक्षिप्त करें',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'संबंध',
 | 
			
		||||
                    primary: 'प्राथमिक तालिका',
 | 
			
		||||
                    foreign: 'संदर्भित तालिका',
 | 
			
		||||
                    cardinality: 'कार्डिनैलिटी',
 | 
			
		||||
@@ -197,19 +191,28 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'हटाएँ',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'कोई संबंध नहीं',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'तालिकाओं को कनेक्ट करने के लिए एक संबंध बनाएँ',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'निर्भरताएँ',
 | 
			
		||||
                filter: 'फ़िल्टर',
 | 
			
		||||
                collapse: 'सिकोड़ें',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'निर्भरता',
 | 
			
		||||
                    table: 'तालिका',
 | 
			
		||||
                    dependent_table: 'आश्रित दृश्य',
 | 
			
		||||
                    delete_dependency: 'हटाएँ',
 | 
			
		||||
                    dependent_table: 'आश्रित तालिका',
 | 
			
		||||
                    delete_dependency: 'निर्भरता हटाएँ',
 | 
			
		||||
                    dependency_actions: {
 | 
			
		||||
                        title: 'क्रियाएँ',
 | 
			
		||||
                        delete_dependency: 'हटाएँ',
 | 
			
		||||
                        title: 'कार्रवाइयाँ',
 | 
			
		||||
                        delete_dependency: 'निर्भरता हटाएँ',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'कोई संबंध नहीं',
 | 
			
		||||
                    description: 'शुरू करने के लिए एक संबंध बनाएँ',
 | 
			
		||||
                    title: 'कोई निर्भरता नहीं',
 | 
			
		||||
                    description: 'इस अनुभाग में कोई निर्भरता उपलब्ध नहीं है।',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -233,35 +236,6 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuals',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'नोट्स',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'फ़िल्टर',
 | 
			
		||||
                add_note: 'नोट जोड़ें',
 | 
			
		||||
                no_results: 'कोई नोट नहीं मिला',
 | 
			
		||||
                clear: 'फ़िल्टर साफ़ करें',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'कोई नोट नहीं',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'कैनवास पर टेक्स्ट एनोटेशन जोड़ने के लिए एक नोट बनाएं',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'खाली नोट',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'नोट क्रियाएं',
 | 
			
		||||
                        edit_content: 'सामग्री संपादित करें',
 | 
			
		||||
                        delete_note: 'नोट हटाएं',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -278,16 +252,12 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'कोई enum मान परिभाषित नहीं',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -301,11 +271,7 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
            show_all: 'सभी दिखाएँ',
 | 
			
		||||
            undo: 'पूर्ववत करें',
 | 
			
		||||
            redo: 'पुनः करें',
 | 
			
		||||
            reorder_diagram: 'आरेख स्वचालित व्यवस्थित करें',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'आरेख पुनः व्यवस्थित करें',
 | 
			
		||||
            highlight_overlapping_tables: 'ओवरलैपिंग तालिकाओं को हाइलाइट करें',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -341,13 +307,13 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
            back: 'वापस',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            empty_diagram: 'खाली डेटाबेस',
 | 
			
		||||
            empty_diagram: 'खाली आरेख',
 | 
			
		||||
            continue: 'जारी रखें',
 | 
			
		||||
            import: 'आयात करें',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'डेटाबेस खोलें',
 | 
			
		||||
            title: 'आरेख खोलें',
 | 
			
		||||
            description: 'नीचे दी गई सूची से एक आरेख चुनें।',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'नाम',
 | 
			
		||||
@@ -357,12 +323,6 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'रद्द करें',
 | 
			
		||||
            open: 'खोलें',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'खोलें',
 | 
			
		||||
                duplicate: 'डुप्लिकेट',
 | 
			
		||||
                delete: 'हटाएं',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -449,14 +409,6 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
            confirm: 'बदलें',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'नया स्कीमा बनाएं',
 | 
			
		||||
            description:
 | 
			
		||||
                'अभी तक कोई स्कीमा मौजूद नहीं है। अपनी तालिकाओं को व्यवस्थित करने के लिए अपना पहला स्कीमा बनाएं।',
 | 
			
		||||
            create: 'बनाएं',
 | 
			
		||||
            cancel: 'रद्द करें',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'हमें सुधारने में मदद करें!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -512,11 +464,9 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'नई तालिका',
 | 
			
		||||
            new_view: 'नया व्यू',
 | 
			
		||||
            new_relationship: 'नया संबंध',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'नया नोट',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -536,9 +486,6 @@ export const hi: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'भाषा बदलें',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'चालू',
 | 
			
		||||
        off: 'बंद',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,538 +0,0 @@
 | 
			
		||||
import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const hr: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Novi',
 | 
			
		||||
            browse: 'Pregledaj',
 | 
			
		||||
            tables: 'Tablice',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Ovisnosti',
 | 
			
		||||
            custom_types: 'Prilagođeni Tipovi',
 | 
			
		||||
            visuals: 'Vizuali',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Akcije',
 | 
			
		||||
                new: 'Novi...',
 | 
			
		||||
                browse: 'Pregledaj...',
 | 
			
		||||
                save: 'Spremi',
 | 
			
		||||
                import: 'Uvezi',
 | 
			
		||||
                export_sql: 'Izvezi SQL',
 | 
			
		||||
                export_as: 'Izvezi kao',
 | 
			
		||||
                delete_diagram: 'Izbriši',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Uredi',
 | 
			
		||||
                undo: 'Poništi',
 | 
			
		||||
                redo: 'Ponovi',
 | 
			
		||||
                clear: 'Očisti',
 | 
			
		||||
            },
 | 
			
		||||
            view: {
 | 
			
		||||
                view: 'Prikaz',
 | 
			
		||||
                show_sidebar: 'Prikaži bočnu traku',
 | 
			
		||||
                hide_sidebar: 'Sakrij bočnu traku',
 | 
			
		||||
                hide_cardinality: 'Sakrij kardinalnost',
 | 
			
		||||
                show_cardinality: 'Prikaži kardinalnost',
 | 
			
		||||
                hide_field_attributes: 'Sakrij atribute polja',
 | 
			
		||||
                show_field_attributes: 'Prikaži atribute polja',
 | 
			
		||||
                zoom_on_scroll: 'Zumiranje pri skrolanju',
 | 
			
		||||
                show_views: 'Pogledi Baze Podataka',
 | 
			
		||||
                theme: 'Tema',
 | 
			
		||||
                show_dependencies: 'Prikaži ovisnosti',
 | 
			
		||||
                hide_dependencies: 'Sakrij ovisnosti',
 | 
			
		||||
                show_minimap: 'Prikaži mini kartu',
 | 
			
		||||
                hide_minimap: 'Sakrij mini kartu',
 | 
			
		||||
            },
 | 
			
		||||
            backup: {
 | 
			
		||||
                backup: 'Sigurnosna kopija',
 | 
			
		||||
                export_diagram: 'Izvezi dijagram',
 | 
			
		||||
                restore_diagram: 'Vrati dijagram',
 | 
			
		||||
            },
 | 
			
		||||
            help: {
 | 
			
		||||
                help: 'Pomoć',
 | 
			
		||||
                docs_website: 'Dokumentacija',
 | 
			
		||||
                join_discord: 'Pridružite nam se na Discordu',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        delete_diagram_alert: {
 | 
			
		||||
            title: 'Izbriši dijagram',
 | 
			
		||||
            description:
 | 
			
		||||
                'Ova radnja se ne može poništiti. Ovo će trajno izbrisati dijagram.',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            delete: 'Izbriši',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        clear_diagram_alert: {
 | 
			
		||||
            title: 'Očisti dijagram',
 | 
			
		||||
            description:
 | 
			
		||||
                'Ova radnja se ne može poništiti. Ovo će trajno izbrisati sve podatke u dijagramu.',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            clear: 'Očisti',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Automatski preuredi dijagram',
 | 
			
		||||
            description:
 | 
			
		||||
                'Ova radnja će preurediti sve tablice u dijagramu. Želite li nastaviti?',
 | 
			
		||||
            reorder: 'Automatski preuredi',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Kopiranje neuspješno',
 | 
			
		||||
                description: 'Međuspremnik nije podržan.',
 | 
			
		||||
            },
 | 
			
		||||
            failed: {
 | 
			
		||||
                title: 'Kopiranje neuspješno',
 | 
			
		||||
                description: 'Nešto je pošlo po zlu. Molimo pokušajte ponovno.',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        theme: {
 | 
			
		||||
            system: 'Sustav',
 | 
			
		||||
            light: 'Svijetla',
 | 
			
		||||
            dark: 'Tamna',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        zoom: {
 | 
			
		||||
            on: 'Uključeno',
 | 
			
		||||
            off: 'Isključeno',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        last_saved: 'Zadnje spremljeno',
 | 
			
		||||
        saved: 'Spremljeno',
 | 
			
		||||
        loading_diagram: 'Učitavanje dijagrama...',
 | 
			
		||||
        deselect_all: 'Odznači sve',
 | 
			
		||||
        select_all: 'Označi sve',
 | 
			
		||||
        clear: 'Očisti',
 | 
			
		||||
        show_more: 'Prikaži više',
 | 
			
		||||
        show_less: 'Prikaži manje',
 | 
			
		||||
        copy_to_clipboard: 'Kopiraj u međuspremnik',
 | 
			
		||||
        copied: 'Kopirano!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            view_all_options: 'Prikaži sve opcije...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Tablice',
 | 
			
		||||
                add_table: 'Dodaj tablicu',
 | 
			
		||||
                add_view: 'Dodaj Pogled',
 | 
			
		||||
                filter: 'Filtriraj',
 | 
			
		||||
                collapse: 'Sažmi sve',
 | 
			
		||||
                clear: 'Očisti filter',
 | 
			
		||||
                no_results:
 | 
			
		||||
                    'Nema pronađenih tablica koje odgovaraju vašem filteru.',
 | 
			
		||||
                show_list: 'Prikaži popis tablica',
 | 
			
		||||
                show_dbml: 'Prikaži DBML uređivač',
 | 
			
		||||
 | 
			
		||||
                table: {
 | 
			
		||||
                    fields: 'Polja',
 | 
			
		||||
                    nullable: 'Može biti null?',
 | 
			
		||||
                    primary_key: 'Primarni ključ',
 | 
			
		||||
                    indexes: 'Indeksi',
 | 
			
		||||
                    comments: 'Komentari',
 | 
			
		||||
                    no_comments: 'Nema komentara',
 | 
			
		||||
                    add_field: 'Dodaj polje',
 | 
			
		||||
                    add_index: 'Dodaj indeks',
 | 
			
		||||
                    index_select_fields: 'Odaberi polja',
 | 
			
		||||
                    no_types_found: 'Nema pronađenih tipova',
 | 
			
		||||
                    field_name: 'Naziv',
 | 
			
		||||
                    field_type: 'Tip',
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Atributi polja',
 | 
			
		||||
                        unique: 'Jedinstven',
 | 
			
		||||
                        auto_increment: 'Automatsko povećavanje',
 | 
			
		||||
                        character_length: 'Maksimalna dužina',
 | 
			
		||||
                        precision: 'Preciznost',
 | 
			
		||||
                        scale: 'Skala',
 | 
			
		||||
                        comments: 'Komentari',
 | 
			
		||||
                        no_comments: 'Nema komentara',
 | 
			
		||||
                        default_value: 'Zadana vrijednost',
 | 
			
		||||
                        no_default: 'Nema zadane vrijednosti',
 | 
			
		||||
                        delete_field: 'Izbriši polje',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'Atributi indeksa',
 | 
			
		||||
                        name: 'Naziv',
 | 
			
		||||
                        unique: 'Jedinstven',
 | 
			
		||||
                        index_type: 'Vrsta indeksa',
 | 
			
		||||
                        delete_index: 'Izbriši indeks',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
                        title: 'Radnje nad tablicom',
 | 
			
		||||
                        change_schema: 'Promijeni shemu',
 | 
			
		||||
                        add_field: 'Dodaj polje',
 | 
			
		||||
                        add_index: 'Dodaj indeks',
 | 
			
		||||
                        duplicate_table: 'Dupliciraj tablicu',
 | 
			
		||||
                        delete_table: 'Izbriši tablicu',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Nema tablica',
 | 
			
		||||
                    description: 'Stvorite tablicu za početak',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Filtriraj',
 | 
			
		||||
                collapse: 'Sažmi sve',
 | 
			
		||||
                add_relationship: 'Dodaj vezu',
 | 
			
		||||
                relationships: 'Veze',
 | 
			
		||||
                dependencies: 'Ovisnosti',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Veza',
 | 
			
		||||
                    primary: 'Primarna tablica',
 | 
			
		||||
                    foreign: 'Referentna tablica',
 | 
			
		||||
                    cardinality: 'Kardinalnost',
 | 
			
		||||
                    delete_relationship: 'Izbriši',
 | 
			
		||||
                    relationship_actions: {
 | 
			
		||||
                        title: 'Radnje',
 | 
			
		||||
                        delete_relationship: 'Izbriši',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Ovisnost',
 | 
			
		||||
                    table: 'Tablica',
 | 
			
		||||
                    dependent_table: 'Ovisni pogled',
 | 
			
		||||
                    delete_dependency: 'Izbriši',
 | 
			
		||||
                    dependency_actions: {
 | 
			
		||||
                        title: 'Radnje',
 | 
			
		||||
                        delete_dependency: 'Izbriši',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Nema veze',
 | 
			
		||||
                    description: 'Stvorite vezu za početak',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            areas_section: {
 | 
			
		||||
                areas: 'Područja',
 | 
			
		||||
                add_area: 'Dodaj područje',
 | 
			
		||||
                filter: 'Filtriraj',
 | 
			
		||||
                clear: 'Očisti filter',
 | 
			
		||||
                no_results:
 | 
			
		||||
                    'Nema pronađenih područja koja odgovaraju vašem filteru.',
 | 
			
		||||
 | 
			
		||||
                area: {
 | 
			
		||||
                    area_actions: {
 | 
			
		||||
                        title: 'Radnje nad područjem',
 | 
			
		||||
                        edit_name: 'Uredi naziv',
 | 
			
		||||
                        delete_area: 'Izbriši područje',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Nema područja',
 | 
			
		||||
                    description: 'Stvorite područje za početak',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Vizuali',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Područja',
 | 
			
		||||
                    notes: 'Bilješke',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Filtriraj',
 | 
			
		||||
                add_note: 'Dodaj Bilješku',
 | 
			
		||||
                no_results: 'Nije pronađena nijedna bilješka',
 | 
			
		||||
                clear: 'Očisti Filter',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Nema Bilješki',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Kreirajte bilješku za dodavanje tekstualnih napomena na platnu',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Prazna bilješka',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Akcije Bilješke',
 | 
			
		||||
                        edit_content: 'Uredi Sadržaj',
 | 
			
		||||
                        delete_note: 'Obriši Bilješku',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Prilagođeni tipovi',
 | 
			
		||||
                filter: 'Filtriraj',
 | 
			
		||||
                clear: 'Očisti filter',
 | 
			
		||||
                no_results:
 | 
			
		||||
                    'Nema pronađenih prilagođenih tipova koji odgovaraju vašem filteru.',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Nema prilagođenih tipova',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Prilagođeni tipovi će se pojaviti ovdje kada budu dostupni u vašoj bazi podataka',
 | 
			
		||||
                },
 | 
			
		||||
                custom_type: {
 | 
			
		||||
                    kind: 'Vrsta',
 | 
			
		||||
                    enum_values: 'Enum vrijednosti',
 | 
			
		||||
                    composite_fields: 'Polja',
 | 
			
		||||
                    no_fields: 'Nema definiranih polja',
 | 
			
		||||
                    no_values: 'Nema definiranih enum vrijednosti',
 | 
			
		||||
                    field_name_placeholder: 'Naziv polja',
 | 
			
		||||
                    field_type_placeholder: 'Odaberi tip',
 | 
			
		||||
                    add_field: 'Dodaj polje',
 | 
			
		||||
                    no_fields_tooltip:
 | 
			
		||||
                        'Nema definiranih polja za ovaj prilagođeni tip',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Radnje',
 | 
			
		||||
                        highlight_fields: 'Istakni polja',
 | 
			
		||||
                        clear_field_highlight: 'Ukloni isticanje',
 | 
			
		||||
                        delete_custom_type: 'Izbriši',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Izbriši tip',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        toolbar: {
 | 
			
		||||
            zoom_in: 'Uvećaj',
 | 
			
		||||
            zoom_out: 'Smanji',
 | 
			
		||||
            save: 'Spremi',
 | 
			
		||||
            show_all: 'Prikaži sve',
 | 
			
		||||
            undo: 'Poništi',
 | 
			
		||||
            redo: 'Ponovi',
 | 
			
		||||
            reorder_diagram: 'Automatski preuredi dijagram',
 | 
			
		||||
            highlight_overlapping_tables: 'Istakni preklapajuće tablice',
 | 
			
		||||
            clear_custom_type_highlight: 'Ukloni isticanje za "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Isticanje "{{typeName}}" - Kliknite za uklanjanje',
 | 
			
		||||
            filter: 'Filtriraj tablice',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        new_diagram_dialog: {
 | 
			
		||||
            database_selection: {
 | 
			
		||||
                title: 'Koja je vaša baza podataka?',
 | 
			
		||||
                description:
 | 
			
		||||
                    'Svaka baza podataka ima svoje jedinstvene značajke i mogućnosti.',
 | 
			
		||||
                check_examples_long: 'Pogledaj primjere',
 | 
			
		||||
                check_examples_short: 'Primjeri',
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            import_database: {
 | 
			
		||||
                title: 'Uvezite svoju bazu podataka',
 | 
			
		||||
                database_edition: 'Verzija baze podataka:',
 | 
			
		||||
                step_1: 'Pokrenite ovu skriptu u svojoj bazi podataka:',
 | 
			
		||||
                step_2: 'Zalijepite rezultat skripte u ovaj dio →',
 | 
			
		||||
                script_results_placeholder: 'Rezultati skripte ovdje...',
 | 
			
		||||
                ssms_instructions: {
 | 
			
		||||
                    button_text: 'SSMS upute',
 | 
			
		||||
                    title: 'Upute',
 | 
			
		||||
                    step_1: 'Idite na Tools > Options > Query Results > SQL Server.',
 | 
			
		||||
                    step_2: 'Ako koristite "Results to Grid," promijenite Maximum Characters Retrieved za Non-XML podatke (postavite na 9999999).',
 | 
			
		||||
                },
 | 
			
		||||
                instructions_link: 'Trebate pomoć? Pogledajte kako',
 | 
			
		||||
                check_script_result: 'Provjeri rezultat skripte',
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            import_from_file: 'Uvezi iz datoteke',
 | 
			
		||||
            back: 'Natrag',
 | 
			
		||||
            empty_diagram: 'Prazna baza podataka',
 | 
			
		||||
            continue: 'Nastavi',
 | 
			
		||||
            import: 'Uvezi',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Otvori bazu podataka',
 | 
			
		||||
            description: 'Odaberite dijagram za otvaranje iz popisa ispod.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'Naziv',
 | 
			
		||||
                created_at: 'Stvoreno',
 | 
			
		||||
                last_modified: 'Zadnje izmijenjeno',
 | 
			
		||||
                tables_count: 'Tablice',
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            open: 'Otvori',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Otvori',
 | 
			
		||||
                duplicate: 'Dupliciraj',
 | 
			
		||||
                delete: 'Obriši',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
            title: 'Izvezi SQL',
 | 
			
		||||
            description:
 | 
			
		||||
                'Izvezite shemu vašeg dijagrama u {{databaseType}} skriptu',
 | 
			
		||||
            close: 'Zatvori',
 | 
			
		||||
            loading: {
 | 
			
		||||
                text: 'AI generira SQL za {{databaseType}}...',
 | 
			
		||||
                description: 'Ovo bi trebalo potrajati do 30 sekundi.',
 | 
			
		||||
            },
 | 
			
		||||
            error: {
 | 
			
		||||
                message:
 | 
			
		||||
                    'Greška pri generiranju SQL skripte. Molimo pokušajte ponovno kasnije ili <0>kontaktirajte nas</0>.',
 | 
			
		||||
                description:
 | 
			
		||||
                    'Slobodno koristite svoj OPENAI_TOKEN, pogledajte priručnik <0>ovdje</0>.',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_relationship_dialog: {
 | 
			
		||||
            title: 'Kreiraj vezu',
 | 
			
		||||
            primary_table: 'Primarna tablica',
 | 
			
		||||
            primary_field: 'Primarno polje',
 | 
			
		||||
            referenced_table: 'Referentna tablica',
 | 
			
		||||
            referenced_field: 'Referentno polje',
 | 
			
		||||
            primary_table_placeholder: 'Odaberi tablicu',
 | 
			
		||||
            primary_field_placeholder: 'Odaberi polje',
 | 
			
		||||
            referenced_table_placeholder: 'Odaberi tablicu',
 | 
			
		||||
            referenced_field_placeholder: 'Odaberi polje',
 | 
			
		||||
            no_tables_found: 'Nema pronađenih tablica',
 | 
			
		||||
            no_fields_found: 'Nema pronađenih polja',
 | 
			
		||||
            create: 'Kreiraj',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        import_database_dialog: {
 | 
			
		||||
            title: 'Uvezi u trenutni dijagram',
 | 
			
		||||
            override_alert: {
 | 
			
		||||
                title: 'Uvezi bazu podataka',
 | 
			
		||||
                content: {
 | 
			
		||||
                    alert: 'Uvoz ovog dijagrama će utjecati na postojeće tablice i veze.',
 | 
			
		||||
                    new_tables:
 | 
			
		||||
                        '<bold>{{newTablesNumber}}</bold> novih tablica će biti dodano.',
 | 
			
		||||
                    new_relationships:
 | 
			
		||||
                        '<bold>{{newRelationshipsNumber}}</bold> novih veza će biti stvoreno.',
 | 
			
		||||
                    tables_override:
 | 
			
		||||
                        '<bold>{{tablesOverrideNumber}}</bold> tablica će biti prepisano.',
 | 
			
		||||
                    proceed: 'Želite li nastaviti?',
 | 
			
		||||
                },
 | 
			
		||||
                import: 'Uvezi',
 | 
			
		||||
                cancel: 'Odustani',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_image_dialog: {
 | 
			
		||||
            title: 'Izvezi sliku',
 | 
			
		||||
            description: 'Odaberite faktor veličine za izvoz:',
 | 
			
		||||
            scale_1x: '1x Obično',
 | 
			
		||||
            scale_2x: '2x (Preporučeno)',
 | 
			
		||||
            scale_3x: '3x',
 | 
			
		||||
            scale_4x: '4x',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            export: 'Izvezi',
 | 
			
		||||
            advanced_options: 'Napredne opcije',
 | 
			
		||||
            pattern: 'Uključi pozadinski uzorak',
 | 
			
		||||
            pattern_description: 'Dodaj suptilni mrežni uzorak u pozadinu.',
 | 
			
		||||
            transparent: 'Prozirna pozadina',
 | 
			
		||||
            transparent_description: 'Ukloni boju pozadine iz slike.',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        new_table_schema_dialog: {
 | 
			
		||||
            title: 'Odaberi shemu',
 | 
			
		||||
            description:
 | 
			
		||||
                'Trenutno je prikazano više shema. Odaberite jednu za novu tablicu.',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            confirm: 'Potvrdi',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        update_table_schema_dialog: {
 | 
			
		||||
            title: 'Promijeni shemu',
 | 
			
		||||
            description: 'Ažuriraj shemu tablice "{{tableName}}"',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            confirm: 'Promijeni',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Stvori novu shemu',
 | 
			
		||||
            description:
 | 
			
		||||
                'Još ne postoje sheme. Stvorite svoju prvu shemu za organiziranje tablica.',
 | 
			
		||||
            create: 'Stvori',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Pomozite nam da se poboljšamo!',
 | 
			
		||||
            description:
 | 
			
		||||
                'Želite li nam dati zvjezdicu na GitHubu? Samo je jedan klik!',
 | 
			
		||||
            close: 'Ne sada',
 | 
			
		||||
            confirm: 'Naravno!',
 | 
			
		||||
        },
 | 
			
		||||
        export_diagram_dialog: {
 | 
			
		||||
            title: 'Izvezi dijagram',
 | 
			
		||||
            description: 'Odaberite format za izvoz:',
 | 
			
		||||
            format_json: 'JSON',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            export: 'Izvezi',
 | 
			
		||||
            error: {
 | 
			
		||||
                title: 'Greška pri izvozu dijagrama',
 | 
			
		||||
                description:
 | 
			
		||||
                    'Nešto je pošlo po zlu. Trebate pomoć? support@chartdb.io',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        import_diagram_dialog: {
 | 
			
		||||
            title: 'Uvezi dijagram',
 | 
			
		||||
            description: 'Uvezite dijagram iz JSON datoteke.',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            import: 'Uvezi',
 | 
			
		||||
            error: {
 | 
			
		||||
                title: 'Greška pri uvozu dijagrama',
 | 
			
		||||
                description:
 | 
			
		||||
                    'JSON dijagrama je nevažeći. Molimo provjerite JSON i pokušajte ponovno. Trebate pomoć? support@chartdb.io',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        import_dbml_dialog: {
 | 
			
		||||
            example_title: 'Uvezi primjer DBML-a',
 | 
			
		||||
            title: 'Uvezi DBML',
 | 
			
		||||
            description: 'Uvezite shemu baze podataka iz DBML formata.',
 | 
			
		||||
            import: 'Uvezi',
 | 
			
		||||
            cancel: 'Odustani',
 | 
			
		||||
            skip_and_empty: 'Preskoči i isprazni',
 | 
			
		||||
            show_example: 'Prikaži primjer',
 | 
			
		||||
            error: {
 | 
			
		||||
                title: 'Greška pri uvozu DBML-a',
 | 
			
		||||
                description:
 | 
			
		||||
                    'Neuspješno parsiranje DBML-a. Molimo provjerite sintaksu.',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        relationship_type: {
 | 
			
		||||
            one_to_one: 'Jedan na jedan',
 | 
			
		||||
            one_to_many: 'Jedan na više',
 | 
			
		||||
            many_to_one: 'Više na jedan',
 | 
			
		||||
            many_to_many: 'Više na više',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Nova tablica',
 | 
			
		||||
            new_view: 'Novi Pogled',
 | 
			
		||||
            new_relationship: 'Nova veza',
 | 
			
		||||
            new_area: 'Novo područje',
 | 
			
		||||
            new_note: 'Nova Bilješka',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
            edit_table: 'Uredi tablicu',
 | 
			
		||||
            duplicate_table: 'Dupliciraj tablicu',
 | 
			
		||||
            delete_table: 'Izbriši tablicu',
 | 
			
		||||
            add_relationship: 'Dodaj vezu',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        snap_to_grid_tooltip: 'Priljepljivanje na mrežu (Drži {{key}})',
 | 
			
		||||
 | 
			
		||||
        tool_tips: {
 | 
			
		||||
            double_click_to_edit: 'Dvostruki klik za uređivanje',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Jezik',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Uključeno',
 | 
			
		||||
        off: 'Isključeno',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const hrMetadata: LanguageMetadata = {
 | 
			
		||||
    name: 'Croatian',
 | 
			
		||||
    nativeName: 'Hrvatski',
 | 
			
		||||
    code: 'hr',
 | 
			
		||||
};
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const id_ID: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Baru',
 | 
			
		||||
            browse: 'Jelajahi',
 | 
			
		||||
            tables: 'Tabel',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Ketergantungan',
 | 
			
		||||
            custom_types: 'Tipe Kustom',
 | 
			
		||||
            visuals: 'Visual',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Aksi',
 | 
			
		||||
                new: 'Baru...',
 | 
			
		||||
                browse: 'Jelajahi...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Berkas',
 | 
			
		||||
                new: 'Buat Baru',
 | 
			
		||||
                open: 'Buka',
 | 
			
		||||
                save: 'Simpan',
 | 
			
		||||
                import: 'Impor Database',
 | 
			
		||||
                export_sql: 'Ekspor SQL',
 | 
			
		||||
                export_as: 'Ekspor Sebagai',
 | 
			
		||||
                delete_diagram: 'Hapus',
 | 
			
		||||
                delete_diagram: 'Hapus Diagram',
 | 
			
		||||
                exit: 'Keluar',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Ubah',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'Sembunyikan Sidebar',
 | 
			
		||||
                hide_cardinality: 'Sembunyikan Kardinalitas',
 | 
			
		||||
                show_cardinality: 'Tampilkan Kardinalitas',
 | 
			
		||||
                hide_field_attributes: 'Sembunyikan Atribut Kolom',
 | 
			
		||||
                show_field_attributes: 'Tampilkan Atribut Kolom',
 | 
			
		||||
                zoom_on_scroll: 'Perbesar saat Scroll',
 | 
			
		||||
                show_views: 'Tampilan Database',
 | 
			
		||||
                theme: 'Tema',
 | 
			
		||||
                show_dependencies: 'Tampilkan Dependensi',
 | 
			
		||||
                hide_dependencies: 'Sembunyikan Dependensi',
 | 
			
		||||
@@ -74,13 +63,22 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Atur Otomatis Diagram',
 | 
			
		||||
            title: 'Atur Ulang Diagram',
 | 
			
		||||
            description:
 | 
			
		||||
                'Tindakan ini akan mengatur ulang semua tabel di diagram. Apakah Anda ingin melanjutkan?',
 | 
			
		||||
            reorder: 'Atur Otomatis',
 | 
			
		||||
            reorder: 'Atur Ulang',
 | 
			
		||||
            cancel: 'Batal',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Schema Lebih dari satu',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} schema di diagram ini. Sedang ditampilkan: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'Tidak ada',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Gagal menyalin',
 | 
			
		||||
@@ -115,11 +113,14 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
        copied: 'Tersalin!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Skema:',
 | 
			
		||||
            filter_by_schema: 'Saring berdasarkan skema',
 | 
			
		||||
            search_schema: 'Cari skema...',
 | 
			
		||||
            no_schemas_found: 'Tidak ada skema yang ditemukan.',
 | 
			
		||||
            view_all_options: 'Tampilkan Semua Pilihan...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Tabel',
 | 
			
		||||
                add_table: 'Tambah Tabel',
 | 
			
		||||
                add_view: 'Tambah Tampilan',
 | 
			
		||||
                filter: 'Saring',
 | 
			
		||||
                collapse: 'Lipat Semua',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -145,7 +146,6 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Atribut Kolom',
 | 
			
		||||
                        unique: 'Unik',
 | 
			
		||||
                        auto_increment: 'Kenaikan Otomatis',
 | 
			
		||||
                        comments: 'Komentar',
 | 
			
		||||
                        no_comments: 'Tidak ada komentar',
 | 
			
		||||
                        delete_field: 'Hapus Kolom',
 | 
			
		||||
@@ -154,14 +154,11 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Presisi',
 | 
			
		||||
                        scale: 'Skala',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'Atribut Indeks',
 | 
			
		||||
                        name: 'Nama',
 | 
			
		||||
                        unique: 'Unik',
 | 
			
		||||
                        index_type: 'Tipe Indeks',
 | 
			
		||||
                        delete_index: 'Hapus Indeks',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -178,15 +175,12 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
                    description: 'Buat tabel untuk memulai',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Saring',
 | 
			
		||||
                collapse: 'Lipat Semua',
 | 
			
		||||
                add_relationship: 'Tambah Hubungan',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Hubungan',
 | 
			
		||||
                dependencies: 'Dependensi',
 | 
			
		||||
                filter: 'Saring',
 | 
			
		||||
                add_relationship: 'Tambah Hubungan',
 | 
			
		||||
                collapse: 'Lipat Semua',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Hubungan',
 | 
			
		||||
                    primary: 'Tabel Primer',
 | 
			
		||||
                    foreign: 'Tabel Referensi',
 | 
			
		||||
                    cardinality: 'Kardinalitas',
 | 
			
		||||
@@ -196,8 +190,16 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'Hapus',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Tidak ada hubungan',
 | 
			
		||||
                    description: 'Buat hubungan untuk menghubungkan tabel',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Dependensi',
 | 
			
		||||
                filter: 'Saring',
 | 
			
		||||
                collapse: 'Lipat Semua',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Dependensi',
 | 
			
		||||
                    table: 'Tabel',
 | 
			
		||||
                    dependent_table: 'Tampilan Dependen',
 | 
			
		||||
                    delete_dependency: 'Hapus',
 | 
			
		||||
@@ -207,8 +209,8 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Tidak ada hubungan',
 | 
			
		||||
                    description: 'Buat hubungan untuk memulai',
 | 
			
		||||
                    title: 'Tidak ada dependensi',
 | 
			
		||||
                    description: 'Buat tampilan untuk memulai',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -232,35 +234,6 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visual',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Catatan',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                add_note: 'Tambah Catatan',
 | 
			
		||||
                no_results: 'Tidak ada catatan ditemukan',
 | 
			
		||||
                clear: 'Hapus Filter',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Tidak Ada Catatan',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Buat catatan untuk menambahkan anotasi teks di kanvas',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Catatan kosong',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Aksi Catatan',
 | 
			
		||||
                        edit_content: 'Edit Konten',
 | 
			
		||||
                        delete_note: 'Hapus Catatan',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -277,16 +250,12 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'Tidak ada nilai enum yang ditentukan',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -300,11 +269,7 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Tampilkan Semua',
 | 
			
		||||
            undo: 'Undo',
 | 
			
		||||
            redo: 'Redo',
 | 
			
		||||
            reorder_diagram: 'Atur Otomatis Diagram',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Atur Ulang Diagram',
 | 
			
		||||
            highlight_overlapping_tables: 'Sorot Tabel yang Tumpang Tindih',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -338,13 +303,13 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
            cancel: 'Batal',
 | 
			
		||||
            import_from_file: 'Impor dari file',
 | 
			
		||||
            back: 'Kembali',
 | 
			
		||||
            empty_diagram: 'Database Kosong',
 | 
			
		||||
            empty_diagram: 'Diagram Kosong',
 | 
			
		||||
            continue: 'Lanjutkan',
 | 
			
		||||
            import: 'Impor',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Buka Database',
 | 
			
		||||
            title: 'Buka Diagram',
 | 
			
		||||
            description: 'Pilih diagram untuk dibuka dari daftar di bawah.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'Name',
 | 
			
		||||
@@ -354,12 +319,6 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Batal',
 | 
			
		||||
            open: 'Buka',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Buka',
 | 
			
		||||
                duplicate: 'Duplikat',
 | 
			
		||||
                delete: 'Hapus',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -445,14 +404,6 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
            confirm: 'Ubah',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Buat Skema Baru',
 | 
			
		||||
            description:
 | 
			
		||||
                'Belum ada skema yang tersedia. Buat skema pertama Anda untuk mengatur tabel-tabel Anda.',
 | 
			
		||||
            create: 'Buat',
 | 
			
		||||
            cancel: 'Batal',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Bantu kami meningkatkan!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -509,11 +460,9 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Tabel Baru',
 | 
			
		||||
            new_view: 'Tampilan Baru',
 | 
			
		||||
            new_relationship: 'Hubungan Baru',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'Catatan Baru',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -532,9 +481,6 @@ export const id_ID: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Bahasa',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Aktif',
 | 
			
		||||
        off: 'Nonaktif',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const ja: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: '新規',
 | 
			
		||||
            browse: '参照',
 | 
			
		||||
            tables: 'テーブル',
 | 
			
		||||
            refs: '参照',
 | 
			
		||||
            dependencies: '依存関係',
 | 
			
		||||
            custom_types: 'カスタムタイプ',
 | 
			
		||||
            visuals: 'ビジュアル',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'アクション',
 | 
			
		||||
                new: '新規...',
 | 
			
		||||
                browse: '参照...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'ファイル',
 | 
			
		||||
                new: '新規',
 | 
			
		||||
                open: '開く',
 | 
			
		||||
                save: '保存',
 | 
			
		||||
                import: 'データベースをインポート',
 | 
			
		||||
                export_sql: 'SQLをエクスポート',
 | 
			
		||||
                export_as: '形式を指定してエクスポート',
 | 
			
		||||
                delete_diagram: '削除',
 | 
			
		||||
                delete_diagram: 'ダイアグラムを削除',
 | 
			
		||||
                exit: '終了',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: '編集',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'サイドバーを非表示',
 | 
			
		||||
                hide_cardinality: 'カーディナリティを非表示',
 | 
			
		||||
                show_cardinality: 'カーディナリティを表示',
 | 
			
		||||
                hide_field_attributes: 'フィールド属性を非表示',
 | 
			
		||||
                show_field_attributes: 'フィールド属性を表示',
 | 
			
		||||
                zoom_on_scroll: 'スクロールでズーム',
 | 
			
		||||
                show_views: 'データベースビュー',
 | 
			
		||||
                theme: 'テーマ',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
                show_dependencies: 'Show Dependencies',
 | 
			
		||||
@@ -76,13 +65,22 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'ダイアグラムを自動配置',
 | 
			
		||||
            title: 'ダイアグラムを並べ替え',
 | 
			
		||||
            description:
 | 
			
		||||
                'この操作によりダイアグラム内のすべてのテーブルが再配置されます。続行しますか?',
 | 
			
		||||
            reorder: '自動配置',
 | 
			
		||||
            reorder: '並べ替え',
 | 
			
		||||
            cancel: 'キャンセル',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: '複数のスキーマ',
 | 
			
		||||
            description:
 | 
			
		||||
                'このダイアグラムには{{schemasCount}}個のスキーマがあります。現在表示中: {{formattedSchemas}}。',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'なし',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'コピー失敗',
 | 
			
		||||
@@ -119,11 +117,14 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
        copied: 'Copied!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'スキーマ:',
 | 
			
		||||
            filter_by_schema: 'スキーマでフィルタ',
 | 
			
		||||
            search_schema: 'スキーマを検索...',
 | 
			
		||||
            no_schemas_found: 'スキーマが見つかりません。',
 | 
			
		||||
            view_all_options: 'すべてのオプションを表示...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'テーブル',
 | 
			
		||||
                add_table: 'テーブルを追加',
 | 
			
		||||
                add_view: 'ビューを追加',
 | 
			
		||||
                filter: 'フィルタ',
 | 
			
		||||
                collapse: 'すべて折りたたむ',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -149,7 +150,6 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'フィールド属性',
 | 
			
		||||
                        unique: 'ユニーク',
 | 
			
		||||
                        auto_increment: 'オートインクリメント',
 | 
			
		||||
                        comments: 'コメント',
 | 
			
		||||
                        no_comments: 'コメントがありません',
 | 
			
		||||
                        delete_field: 'フィールドを削除',
 | 
			
		||||
@@ -158,14 +158,11 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: '精度',
 | 
			
		||||
                        scale: '小数点以下桁数',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'インデックス属性',
 | 
			
		||||
                        name: '名前',
 | 
			
		||||
                        unique: 'ユニーク',
 | 
			
		||||
                        index_type: 'インデックスタイプ',
 | 
			
		||||
                        delete_index: 'インデックスを削除',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -182,15 +179,12 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
                    description: 'テーブルを作成して開始してください',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: '参照',
 | 
			
		||||
                filter: 'フィルタ',
 | 
			
		||||
                collapse: 'すべて折りたたむ',
 | 
			
		||||
                add_relationship: 'リレーションシップを追加',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'リレーションシップ',
 | 
			
		||||
                dependencies: '依存関係',
 | 
			
		||||
                filter: 'フィルタ',
 | 
			
		||||
                add_relationship: 'リレーションシップを追加',
 | 
			
		||||
                collapse: 'すべて折りたたむ',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'リレーションシップ',
 | 
			
		||||
                    primary: '主テーブル',
 | 
			
		||||
                    foreign: '参照テーブル',
 | 
			
		||||
                    cardinality: 'カーディナリティ',
 | 
			
		||||
@@ -200,20 +194,29 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: '削除',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: '依存関係',
 | 
			
		||||
                    table: 'テーブル',
 | 
			
		||||
                    dependent_table: '依存ビュー',
 | 
			
		||||
                    delete_dependency: '削除',
 | 
			
		||||
                    dependency_actions: {
 | 
			
		||||
                        title: '操作',
 | 
			
		||||
                        delete_dependency: '削除',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'リレーションシップがありません',
 | 
			
		||||
                    description:
 | 
			
		||||
                        '開始するためにリレーションシップを作成してください',
 | 
			
		||||
                        'テーブルを接続するためにリレーションシップを作成してください',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Dependencies',
 | 
			
		||||
                filter: 'Filter',
 | 
			
		||||
                collapse: 'Collapse All',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    table: 'Table',
 | 
			
		||||
                    dependent_table: 'Dependent View',
 | 
			
		||||
                    delete_dependency: 'Delete',
 | 
			
		||||
                    dependency_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        delete_dependency: 'Delete',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'No dependencies',
 | 
			
		||||
                    description: 'Create a view to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -237,35 +240,6 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'ビジュアル',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'ノート',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'フィルター',
 | 
			
		||||
                add_note: 'ノートを追加',
 | 
			
		||||
                no_results: 'ノートが見つかりません',
 | 
			
		||||
                clear: 'フィルターをクリア',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'ノートがありません',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'キャンバス上にテキスト注釈を追加するためのノートを作成',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: '空のノート',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'ノートアクション',
 | 
			
		||||
                        edit_content: 'コンテンツを編集',
 | 
			
		||||
                        delete_note: 'ノートを削除',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -282,16 +256,12 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: '列挙値が定義されていません',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -305,12 +275,10 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
            show_all: 'すべて表示',
 | 
			
		||||
            undo: '元に戻す',
 | 
			
		||||
            redo: 'やり直し',
 | 
			
		||||
            reorder_diagram: 'ダイアグラムを自動配置',
 | 
			
		||||
            reorder_diagram: 'ダイアグラムを並べ替え',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            highlight_overlapping_tables: 'Highlight Overlapping Tables',
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear', // TODO: Translate
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@@ -343,13 +311,13 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
            back: '戻る',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            empty_diagram: '空のデータベース',
 | 
			
		||||
            empty_diagram: '空のダイアグラム',
 | 
			
		||||
            continue: '続行',
 | 
			
		||||
            import: 'インポート',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'データベースを開く',
 | 
			
		||||
            title: 'ダイアグラムを開く',
 | 
			
		||||
            description: '以下のリストからダイアグラムを選択してください。',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: '名前',
 | 
			
		||||
@@ -359,12 +327,6 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'キャンセル',
 | 
			
		||||
            open: '開く',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: '開く',
 | 
			
		||||
                duplicate: '複製',
 | 
			
		||||
                delete: '削除',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -451,14 +413,6 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
            confirm: '変更',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: '新しいスキーマを作成',
 | 
			
		||||
            description:
 | 
			
		||||
                'スキーマがまだ存在しません。テーブルを整理するために最初のスキーマを作成してください。',
 | 
			
		||||
            create: '作成',
 | 
			
		||||
            cancel: 'キャンセル',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: '改善をサポートしてください!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -514,11 +468,9 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: '新しいテーブル',
 | 
			
		||||
            new_view: '新しいビュー',
 | 
			
		||||
            new_relationship: '新しいリレーションシップ',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: '新しいメモ',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -538,9 +490,6 @@ export const ja: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: '言語',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'オン',
 | 
			
		||||
        off: 'オフ',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const ko_KR: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: '새로 만들기',
 | 
			
		||||
            browse: '찾아보기',
 | 
			
		||||
            tables: '테이블',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: '종속성',
 | 
			
		||||
            custom_types: '사용자 지정 타입',
 | 
			
		||||
            visuals: '시각화',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: '작업',
 | 
			
		||||
                new: '새로 만들기...',
 | 
			
		||||
                browse: '찾아보기...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: '파일',
 | 
			
		||||
                new: '새 다이어그램',
 | 
			
		||||
                open: '열기',
 | 
			
		||||
                save: '저장',
 | 
			
		||||
                import: '데이터베이스 가져오기',
 | 
			
		||||
                export_sql: 'SQL로 저장',
 | 
			
		||||
                export_as: '다른 형식으로 저장',
 | 
			
		||||
                delete_diagram: '삭제',
 | 
			
		||||
                delete_diagram: '다이어그램 삭제',
 | 
			
		||||
                exit: '종료',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: '편집',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: '사이드바 숨기기',
 | 
			
		||||
                hide_cardinality: '카디널리티 숨기기',
 | 
			
		||||
                show_cardinality: '카디널리티 보이기',
 | 
			
		||||
                hide_field_attributes: '필드 속성 숨기기',
 | 
			
		||||
                show_field_attributes: '필드 속성 보이기',
 | 
			
		||||
                zoom_on_scroll: '스크롤 시 확대',
 | 
			
		||||
                show_views: '데이터베이스 뷰',
 | 
			
		||||
                theme: '테마',
 | 
			
		||||
                show_dependencies: '종속성 보이기',
 | 
			
		||||
                hide_dependencies: '종속성 숨기기',
 | 
			
		||||
@@ -74,13 +63,22 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: '다이어그램 자동 정렬',
 | 
			
		||||
            title: '다이어그램 재정렬',
 | 
			
		||||
            description:
 | 
			
		||||
                '이 작업은 모든 다이어그램이 재정렬됩니다. 계속하시겠습니까?',
 | 
			
		||||
            reorder: '자동 정렬',
 | 
			
		||||
            reorder: '재정렬',
 | 
			
		||||
            cancel: '취소',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: '다중 스키마',
 | 
			
		||||
            description:
 | 
			
		||||
                '현재 다이어그램에 {{schemasCount}}개의 스키마가 있습니다. Currently displaying: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: '없음',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: '복사 실패',
 | 
			
		||||
@@ -115,11 +113,14 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
        copied: '복사됨!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: '스키마:',
 | 
			
		||||
            filter_by_schema: '스키마로 필터링',
 | 
			
		||||
            search_schema: '스키마 검색...',
 | 
			
		||||
            no_schemas_found: '스키마를 찾을 수 없습니다.',
 | 
			
		||||
            view_all_options: '전체 옵션 보기...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: '테이블',
 | 
			
		||||
                add_table: '테이블 추가',
 | 
			
		||||
                add_view: '뷰 추가',
 | 
			
		||||
                filter: '필터',
 | 
			
		||||
                collapse: '모두 접기',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -145,7 +146,6 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: '필드 속성',
 | 
			
		||||
                        unique: '유니크 여부',
 | 
			
		||||
                        auto_increment: '자동 증가',
 | 
			
		||||
                        comments: '주석',
 | 
			
		||||
                        no_comments: '주석 없음',
 | 
			
		||||
                        delete_field: '필드 삭제',
 | 
			
		||||
@@ -154,14 +154,11 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: '정밀도',
 | 
			
		||||
                        scale: '소수점 자릿수',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: '인덱스 속성',
 | 
			
		||||
                        name: '인덱스 명',
 | 
			
		||||
                        unique: '유니크 여부',
 | 
			
		||||
                        index_type: '인덱스 타입',
 | 
			
		||||
                        delete_index: '인덱스 삭제',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -178,15 +175,12 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
                    description: '테이블을 만들어 시작하세요.',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: '필터',
 | 
			
		||||
                collapse: '모두 접기',
 | 
			
		||||
                add_relationship: '연관 관계 추가',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: '연관 관계',
 | 
			
		||||
                dependencies: '종속성',
 | 
			
		||||
                filter: '필터',
 | 
			
		||||
                add_relationship: '연관 관계 추가',
 | 
			
		||||
                collapse: '모두 접기',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: '연관 관계',
 | 
			
		||||
                    primary: '주 테이블',
 | 
			
		||||
                    foreign: '참조 테이블',
 | 
			
		||||
                    cardinality: '카디널리티',
 | 
			
		||||
@@ -196,8 +190,16 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: '연관 관계 삭제',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '연관 관계',
 | 
			
		||||
                    description: '테이블 연결을 위해 연관 관계를 생성하세요',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: '종속성',
 | 
			
		||||
                filter: '필터',
 | 
			
		||||
                collapse: '모두 접기',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: '종속성',
 | 
			
		||||
                    table: '테이블',
 | 
			
		||||
                    dependent_table: '뷰 테이블',
 | 
			
		||||
                    delete_dependency: '삭제',
 | 
			
		||||
@@ -207,8 +209,8 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '연관 관계 없음',
 | 
			
		||||
                    description: '연관 관계를 만들어 시작하세요.',
 | 
			
		||||
                    title: '뷰 테이블 없음',
 | 
			
		||||
                    description: '뷰 테이블을 만들어 시작하세요.',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -232,35 +234,6 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: '시각화',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: '메모',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: '필터',
 | 
			
		||||
                add_note: '메모 추가',
 | 
			
		||||
                no_results: '메모를 찾을 수 없습니다',
 | 
			
		||||
                clear: '필터 지우기',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '메모 없음',
 | 
			
		||||
                    description:
 | 
			
		||||
                        '캔버스에 텍스트 주석을 추가하려면 메모를 만드세요',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: '빈 메모',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: '메모 작업',
 | 
			
		||||
                        edit_content: '내용 편집',
 | 
			
		||||
                        delete_note: '메모 삭제',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -277,16 +250,12 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: '정의된 열거형 값이 없습니다',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -300,11 +269,7 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
            show_all: '전체 저장',
 | 
			
		||||
            undo: '실행 취소',
 | 
			
		||||
            redo: '다시 실행',
 | 
			
		||||
            reorder_diagram: '다이어그램 자동 정렬',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: '다이어그램 재정렬',
 | 
			
		||||
            highlight_overlapping_tables: '겹치는 테이블 강조 표시',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -338,13 +303,13 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
            cancel: '취소',
 | 
			
		||||
            back: '뒤로가기',
 | 
			
		||||
            import_from_file: '파일에서 가져오기',
 | 
			
		||||
            empty_diagram: '빈 데이터베이스',
 | 
			
		||||
            empty_diagram: '빈 다이어그램으로 시작',
 | 
			
		||||
            continue: '계속',
 | 
			
		||||
            import: '가져오기',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: '데이터베이스 열기',
 | 
			
		||||
            title: '다이어그램 열기',
 | 
			
		||||
            description: '아래의 목록에서 다이어그램을 선택하세요.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: '이름',
 | 
			
		||||
@@ -354,12 +319,6 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: '취소',
 | 
			
		||||
            open: '열기',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: '열기',
 | 
			
		||||
                duplicate: '복제',
 | 
			
		||||
                delete: '삭제',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -445,14 +404,6 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
            confirm: '변경',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: '새 스키마 생성',
 | 
			
		||||
            description:
 | 
			
		||||
                '아직 스키마가 없습니다. 테이블을 정리하기 위해 첫 번째 스키마를 생성하세요.',
 | 
			
		||||
            create: '생성',
 | 
			
		||||
            cancel: '취소',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: '개선할 수 있도록 도와주세요!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -506,11 +457,9 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: '새 테이블',
 | 
			
		||||
            new_view: '새 뷰',
 | 
			
		||||
            new_relationship: '새 연관관계',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: '새 메모',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -529,9 +478,6 @@ export const ko_KR: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: '언어',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: '켜기',
 | 
			
		||||
        off: '끄기',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const mr: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'नवीन',
 | 
			
		||||
            browse: 'ब्राउज',
 | 
			
		||||
            tables: 'टेबल',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'अवलंबने',
 | 
			
		||||
            custom_types: 'कस्टम प्रकार',
 | 
			
		||||
            visuals: 'Visuals',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'क्रिया',
 | 
			
		||||
                new: 'नवीन...',
 | 
			
		||||
                browse: 'ब्राउज करा...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'फाइल',
 | 
			
		||||
                new: 'नवीन',
 | 
			
		||||
                open: 'उघडा',
 | 
			
		||||
                save: 'जतन करा',
 | 
			
		||||
                import: 'डेटाबेस इम्पोर्ट करा',
 | 
			
		||||
                export_sql: 'SQL एक्स्पोर्ट करा',
 | 
			
		||||
                export_as: 'म्हणून एक्स्पोर्ट करा',
 | 
			
		||||
                delete_diagram: 'हटवा',
 | 
			
		||||
                delete_diagram: 'आरेख हटवा',
 | 
			
		||||
                exit: 'बाहेर पडा',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'संपादन करा',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'साइडबार लपवा',
 | 
			
		||||
                hide_cardinality: 'कार्डिनॅलिटी लपवा',
 | 
			
		||||
                show_cardinality: 'कार्डिनॅलिटी दाखवा',
 | 
			
		||||
                hide_field_attributes: 'फील्ड गुणधर्म लपवा',
 | 
			
		||||
                show_field_attributes: 'फील्ड गुणधर्म दाखवा',
 | 
			
		||||
                zoom_on_scroll: 'स्क्रोलवर झूम करा',
 | 
			
		||||
                show_views: 'डेटाबेस व्ह्यूज',
 | 
			
		||||
                theme: 'थीम',
 | 
			
		||||
                show_dependencies: 'डिपेंडेन्सि दाखवा',
 | 
			
		||||
                hide_dependencies: 'डिपेंडेन्सि लपवा',
 | 
			
		||||
@@ -75,13 +64,22 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'आरेख स्वयंचलित व्यवस्थित करा',
 | 
			
		||||
            title: 'आरेख पुनःक्रमित करा',
 | 
			
		||||
            description:
 | 
			
		||||
                'ही क्रिया आरेखातील सर्व टेबल्सची पुनर्रचना करेल. तुम्हाला पुढे जायचे आहे का?',
 | 
			
		||||
            reorder: 'स्वयंचलित व्यवस्थित करा',
 | 
			
		||||
            reorder: 'पुनःक्रमित करा',
 | 
			
		||||
            cancel: 'रद्द करा',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'एकाधिक स्कीमा',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} स्कीमा या आरेखात आहेत. सध्या दाखवत आहोत: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'काहीही नाही',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'कॉपी अयशस्वी',
 | 
			
		||||
@@ -118,11 +116,14 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
        copied: 'Copied!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'स्कीमा:',
 | 
			
		||||
            filter_by_schema: 'स्कीमा द्वारे फिल्टर करा',
 | 
			
		||||
            search_schema: 'स्कीमा शोधा...',
 | 
			
		||||
            no_schemas_found: 'कोणतेही स्कीमा सापडले नाहीत.',
 | 
			
		||||
            view_all_options: 'सर्व पर्याय पहा...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'टेबल्स',
 | 
			
		||||
                add_table: 'टेबल जोडा',
 | 
			
		||||
                add_view: 'व्ह्यू जोडा',
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                collapse: 'सर्व संकुचित करा',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -148,7 +149,6 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'फील्ड गुणधर्म',
 | 
			
		||||
                        unique: 'युनिक',
 | 
			
		||||
                        auto_increment: 'ऑटो इंक्रिमेंट',
 | 
			
		||||
                        comments: 'टिप्पण्या',
 | 
			
		||||
                        no_comments: 'कोणत्याही टिप्पणी नाहीत',
 | 
			
		||||
                        delete_field: 'फील्ड हटवा',
 | 
			
		||||
@@ -157,14 +157,11 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'अचूकता',
 | 
			
		||||
                        scale: 'प्रमाण',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'इंडेक्स गुणधर्म',
 | 
			
		||||
                        name: 'नाव',
 | 
			
		||||
                        unique: 'युनिक',
 | 
			
		||||
                        index_type: 'इंडेक्स प्रकार',
 | 
			
		||||
                        delete_index: 'इंडेक्स हटवा',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -182,15 +179,12 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
                    description: 'सुरू करण्यासाठी एक टेबल तयार करा',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                collapse: 'सर्व संकुचित करा',
 | 
			
		||||
                add_relationship: 'रिलेशनशिप जोडा',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'रिलेशनशिप',
 | 
			
		||||
                dependencies: 'डिपेंडेन्सि',
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                add_relationship: 'रिलेशनशिप जोडा',
 | 
			
		||||
                collapse: 'सर्व संकुचित करा',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'रिलेशनशिप',
 | 
			
		||||
                    primary: 'प्राथमिक टेबल',
 | 
			
		||||
                    foreign: 'रेफरंस टेबल',
 | 
			
		||||
                    cardinality: 'कार्डिनॅलिटी',
 | 
			
		||||
@@ -200,8 +194,17 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'हटवा',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'कोणतेही रिलेशनशिप नाहीत',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'टेबल्स कनेक्ट करण्यासाठी एक रिलेशनशिप तयार करा',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'डिपेंडेन्सि',
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                collapse: 'सर्व संकुचित करा',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'डिपेंडेन्सि',
 | 
			
		||||
                    table: 'टेबल',
 | 
			
		||||
                    dependent_table: 'डिपेंडेन्सि दृश्य',
 | 
			
		||||
                    delete_dependency: 'हटवा',
 | 
			
		||||
@@ -211,8 +214,8 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'कोणतेही रिलेशनशिप नाहीत',
 | 
			
		||||
                    description: 'सुरू करण्यासाठी एक रिलेशनशिप तयार करा',
 | 
			
		||||
                    title: 'कोणत्याही डिपेंडेन्सि नाहीत',
 | 
			
		||||
                    description: 'सुरू करण्यासाठी एक दृश्य तयार करा',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -236,35 +239,6 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuals',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'नोट्स',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                add_note: 'नोट जोडा',
 | 
			
		||||
                no_results: 'कोणत्याही नोट्स सापडल्या नाहीत',
 | 
			
		||||
                clear: 'फिल्टर साफ करा',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'नोट्स नाहीत',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'कॅनव्हासवर मजकूर भाष्य जोडण्यासाठी एक नोट तयार करा',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'रिकामी नोट',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'नोट क्रिया',
 | 
			
		||||
                        edit_content: 'सामग्री संपादित करा',
 | 
			
		||||
                        delete_note: 'नोट हटवा',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -281,16 +255,12 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'कोणतीही enum मूल्ये परिभाषित नाहीत',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -304,11 +274,7 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
            show_all: 'सर्व दाखवा',
 | 
			
		||||
            undo: 'पूर्ववत करा',
 | 
			
		||||
            redo: 'पुन्हा करा',
 | 
			
		||||
            reorder_diagram: 'आरेख स्वयंचलित व्यवस्थित करा',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'आरेख पुनःक्रमित करा',
 | 
			
		||||
            highlight_overlapping_tables: 'ओव्हरलॅपिंग टेबल्स हायलाइट करा',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -344,13 +310,13 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
            // TODO: Add translations
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            back: 'मागे',
 | 
			
		||||
            empty_diagram: 'रिक्त डेटाबेस',
 | 
			
		||||
            empty_diagram: 'रिक्त आरेख',
 | 
			
		||||
            continue: 'सुरू ठेवा',
 | 
			
		||||
            import: 'आयात करा',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'डेटाबेस उघडा',
 | 
			
		||||
            title: 'आरेख उघडा',
 | 
			
		||||
            description: 'खालील यादीतून उघडण्यासाठी एक आरेख निवडा.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'नाव',
 | 
			
		||||
@@ -360,12 +326,6 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'रद्द करा',
 | 
			
		||||
            open: 'उघडा',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'उघडा',
 | 
			
		||||
                duplicate: 'डुप्लिकेट',
 | 
			
		||||
                delete: 'हटवा',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -452,14 +412,6 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
            confirm: 'बदला',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'नवीन स्कीमा तयार करा',
 | 
			
		||||
            description:
 | 
			
		||||
                'अजून कोणतीही स्कीमा अस्तित्वात नाही. आपल्या टेबल्स व्यवस्थित करण्यासाठी आपली पहिली स्कीमा तयार करा.',
 | 
			
		||||
            create: 'तयार करा',
 | 
			
		||||
            cancel: 'रद्द करा',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'आम्हाला सुधारण्यास मदत करा!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -518,11 +470,9 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'नवीन टेबल',
 | 
			
		||||
            new_view: 'नवीन व्ह्यू',
 | 
			
		||||
            new_relationship: 'नवीन रिलेशनशिप',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'नवीन टीप',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -543,9 +493,6 @@ export const mr: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'भाषा बदला',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'चालू',
 | 
			
		||||
        off: 'बंद',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const ne: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'नयाँ',
 | 
			
		||||
            browse: 'ब्राउज',
 | 
			
		||||
            tables: 'टेबलहरू',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'निर्भरताहरू',
 | 
			
		||||
            custom_types: 'कस्टम प्रकारहरू',
 | 
			
		||||
            visuals: 'Visuals',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'कार्यहरू',
 | 
			
		||||
                new: 'नयाँ...',
 | 
			
		||||
                browse: 'ब्राउज गर्नुहोस्...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'फाइल',
 | 
			
		||||
                new: 'नयाँ',
 | 
			
		||||
                open: 'खोल्नुहोस्',
 | 
			
		||||
                save: 'सुरक्षित गर्नुहोस्',
 | 
			
		||||
                import: 'डाटाबेस आयात गर्नुहोस्',
 | 
			
		||||
                export_sql: 'SQL निर्यात गर्नुहोस्',
 | 
			
		||||
                export_as: 'निर्यात गर्नुहोस्',
 | 
			
		||||
                delete_diagram: 'हटाउनुहोस्',
 | 
			
		||||
                delete_diagram: 'डायाग्राम हटाउनुहोस्',
 | 
			
		||||
                exit: 'बाहिर निस्कनुहोस्',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'सम्पादन',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'साइडबार लुकाउनुहोस्',
 | 
			
		||||
                hide_cardinality: 'कार्डिन्यालिटी लुकाउनुहोस्',
 | 
			
		||||
                show_cardinality: 'कार्डिन्यालिटी देखाउनुहोस्',
 | 
			
		||||
                hide_field_attributes: 'फिल्ड विशेषताहरू लुकाउनुहोस्',
 | 
			
		||||
                show_field_attributes: 'फिल्ड विशेषताहरू देखाउनुहोस्',
 | 
			
		||||
                zoom_on_scroll: 'स्क्रोलमा जुम गर्नुहोस्',
 | 
			
		||||
                show_views: 'डाटाबेस भ्यूहरू',
 | 
			
		||||
                theme: 'थिम',
 | 
			
		||||
                show_dependencies: 'डिपेन्डेन्सीहरू देखाउनुहोस्',
 | 
			
		||||
                hide_dependencies: 'डिपेन्डेन्सीहरू लुकाउनुहोस्',
 | 
			
		||||
@@ -75,13 +64,22 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'डायाग्राम स्वचालित मिलाउनुहोस्',
 | 
			
		||||
            title: 'डायाग्राम पुनः क्रमबद्ध गर्नुहोस्',
 | 
			
		||||
            description:
 | 
			
		||||
                'यो कार्य पूर्ववत गर्न सकिँदैन। यो डायाग्राम स्थायी रूपमा हटाउनेछ।',
 | 
			
		||||
            reorder: 'स्वचालित मिलाउनुहोस्',
 | 
			
		||||
            reorder: 'पुनः क्रमबद्ध गर्नुहोस्',
 | 
			
		||||
            cancel: 'रद्द गर्नुहोस्',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'विविध स्कीमहरू',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} डायाग्राममा स्कीमहरू। हालको रूपमा देखाइएको छ: {{formattedSchemas}}।',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'कुनै पनि छैन',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'प्रतिलिपि असफल',
 | 
			
		||||
@@ -116,11 +114,14 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
        copied: 'प्रतिलिपि गरियो!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'स्कीम:',
 | 
			
		||||
            filter_by_schema: 'स्कीम अनुसार फिल्टर गर्नुहोस्',
 | 
			
		||||
            search_schema: 'स्कीम खोज्नुहोस्...',
 | 
			
		||||
            no_schemas_found: 'कुनै स्कीमहरू फेला परेनन्',
 | 
			
		||||
            view_all_options: 'सबै विकल्पहरू हेर्नुहोस्',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'तालिकाहरू',
 | 
			
		||||
                add_table: 'तालिका थप्नुहोस्',
 | 
			
		||||
                add_view: 'भ्यू थप्नुहोस्',
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                collapse: 'सबै लुकाउनुहोस्',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -146,7 +147,6 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'क्षेत्र विशेषताहरू',
 | 
			
		||||
                        unique: 'अनन्य',
 | 
			
		||||
                        auto_increment: 'स्वचालित वृद्धि',
 | 
			
		||||
                        comments: 'टिप्पणीहरू',
 | 
			
		||||
                        no_comments: 'कुनै टिप्पणीहरू छैनन्',
 | 
			
		||||
                        delete_field: 'क्षेत्र हटाउनुहोस्',
 | 
			
		||||
@@ -155,14 +155,11 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'परिशुद्धता',
 | 
			
		||||
                        scale: 'स्केल',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'सूचक विशेषताहरू',
 | 
			
		||||
                        name: 'नाम',
 | 
			
		||||
                        unique: 'अनन्य',
 | 
			
		||||
                        index_type: 'इन्डेक्स प्रकार',
 | 
			
		||||
                        delete_index: 'सूचक हटाउनुहोस्',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -179,15 +176,12 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
                    description: 'सुरु गर्नका लागि एक तालिका बनाउनुहोस्',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                collapse: 'सबै लुकाउनुहोस्',
 | 
			
		||||
                add_relationship: 'सम्बन्ध थप्नुहोस्',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'सम्बन्धहरू',
 | 
			
		||||
                dependencies: 'डिपेन्डेन्सीहरू',
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                add_relationship: 'सम्बन्ध थप्नुहोस्',
 | 
			
		||||
                collapse: 'सबै लुकाउनुहोस्',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'सम्बन्ध',
 | 
			
		||||
                    primary: 'मुख्य तालिका',
 | 
			
		||||
                    foreign: 'परिचित तालिका',
 | 
			
		||||
                    cardinality: 'कार्डिन्यालिटी',
 | 
			
		||||
@@ -197,8 +191,16 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'हटाउनुहोस्',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'कुनै सम्बन्धहरू छैनन्',
 | 
			
		||||
                    description: 'तालिकाहरू जोड्नका लागि एक सम्बन्ध बनाउनुहोस्',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'डिपेन्डेन्सीहरू',
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                collapse: 'सबै लुकाउनुहोस्',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'डिपेन्डेन्सी',
 | 
			
		||||
                    table: 'तालिका',
 | 
			
		||||
                    dependent_table: 'विचलित तालिका',
 | 
			
		||||
                    delete_dependency: 'हटाउनुहोस्',
 | 
			
		||||
@@ -208,8 +210,9 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'कुनै सम्बन्धहरू छैनन्',
 | 
			
		||||
                    description: 'सुरु गर्नका लागि एक सम्बन्ध बनाउनुहोस्',
 | 
			
		||||
                    title: 'कुनै डिपेन्डेन्सीहरू छैनन्',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'डिपेन्डेन्सीहरू देखाउनका लागि एक व्यू बनाउनुहोस्',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -233,35 +236,6 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuals',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'टिप्पणीहरू',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'फिल्टर',
 | 
			
		||||
                add_note: 'टिप्पणी थप्नुहोस्',
 | 
			
		||||
                no_results: 'कुनै टिप्पणी फेला परेन',
 | 
			
		||||
                clear: 'फिल्टर खाली गर्नुहोस्',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'कुनै टिप्पणी छैन',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'क्यानभासमा पाठ टिप्पणी थप्न टिप्पणी सिर्जना गर्नुहोस्',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'खाली टिप्पणी',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'टिप्पणी कार्यहरू',
 | 
			
		||||
                        edit_content: 'सामग्री सम्पादन गर्नुहोस्',
 | 
			
		||||
                        delete_note: 'टिप्पणी मेटाउनुहोस्',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -278,16 +252,12 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'कुनै enum मानहरू परिभाषित छैनन्',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -301,11 +271,7 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
            show_all: 'सबै देखाउनुहोस्',
 | 
			
		||||
            undo: 'पूर्ववत',
 | 
			
		||||
            redo: 'पुनः गर्नुहोस्',
 | 
			
		||||
            reorder_diagram: 'डायाग्राम स्वचालित मिलाउनुहोस्',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'पुनः क्रमबद्ध गर्नुहोस्',
 | 
			
		||||
            highlight_overlapping_tables:
 | 
			
		||||
                'अतिरिक्त तालिकाहरू हाइलाइट गर्नुहोस्',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
@@ -340,13 +306,13 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
            cancel: 'रद्द गर्नुहोस्',
 | 
			
		||||
            import_from_file: 'फाइलबाट आयात गर्नुहोस्',
 | 
			
		||||
            back: 'फर्क',
 | 
			
		||||
            empty_diagram: 'खाली डाटाबेस',
 | 
			
		||||
            empty_diagram: 'रिक्त डायाग्राम',
 | 
			
		||||
            continue: 'जारी राख्नुहोस्',
 | 
			
		||||
            import: 'आयात गर्नुहोस्',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'डाटाबेस खोल्नुहोस्',
 | 
			
		||||
            title: 'डायाग्राम खोल्नुहोस्',
 | 
			
		||||
            description:
 | 
			
		||||
                'तलको सूचीबाट खोल्नका लागि एक डायाग्राम चयन गर्नुहोस्।',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
@@ -357,12 +323,6 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'रद्द गर्नुहोस्',
 | 
			
		||||
            open: 'खोल्नुहोस्',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'खोल्नुहोस्',
 | 
			
		||||
                duplicate: 'डुप्लिकेट',
 | 
			
		||||
                delete: 'मेटाउनुहोस्',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -449,14 +409,6 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
            confirm: 'परिवर्तन गर्नुहोस्',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'नयाँ स्कीम सिर्जना गर्नुहोस्',
 | 
			
		||||
            description:
 | 
			
		||||
                'अहिलेसम्म कुनै स्कीम अस्तित्वमा छैन। आफ्ना तालिकाहरू व्यवस्थित गर्न आफ्नो पहिलो स्कीम सिर्जना गर्नुहोस्।',
 | 
			
		||||
            create: 'सिर्जना गर्नुहोस्',
 | 
			
		||||
            cancel: 'रद्द गर्नुहोस्',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'हामीलाई अझ राम्रो हुन मदत गर्नुहोस!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -512,11 +464,9 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'नयाँ तालिका',
 | 
			
		||||
            new_view: 'नयाँ भ्यू',
 | 
			
		||||
            new_relationship: 'नयाँ सम्बन्ध',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'नयाँ नोट',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -535,9 +485,6 @@ export const ne: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'भाषा परिवर्तन गर्नुहोस्',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'सक्रिय',
 | 
			
		||||
        off: 'निष्क्रिय',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const pt_BR: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Novo',
 | 
			
		||||
            browse: 'Navegar',
 | 
			
		||||
            tables: 'Tabelas',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Dependências',
 | 
			
		||||
            custom_types: 'Tipos Personalizados',
 | 
			
		||||
            visuals: 'Visuais',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Ações',
 | 
			
		||||
                new: 'Novo...',
 | 
			
		||||
                browse: 'Navegar...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Arquivo',
 | 
			
		||||
                new: 'Novo',
 | 
			
		||||
                open: 'Abrir',
 | 
			
		||||
                save: 'Salvar',
 | 
			
		||||
                import: 'Importar Banco de Dados',
 | 
			
		||||
                export_sql: 'Exportar SQL',
 | 
			
		||||
                export_as: 'Exportar como',
 | 
			
		||||
                delete_diagram: 'Excluir',
 | 
			
		||||
                delete_diagram: 'Excluir Diagrama',
 | 
			
		||||
                exit: 'Sair',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Editar',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'Ocultar Barra Lateral',
 | 
			
		||||
                hide_cardinality: 'Ocultar Cardinalidade',
 | 
			
		||||
                show_cardinality: 'Mostrar Cardinalidade',
 | 
			
		||||
                hide_field_attributes: 'Ocultar Atributos de Campo',
 | 
			
		||||
                show_field_attributes: 'Mostrar Atributos de Campo',
 | 
			
		||||
                zoom_on_scroll: 'Zoom ao Rolar',
 | 
			
		||||
                show_views: 'Visualizações do Banco de Dados',
 | 
			
		||||
                theme: 'Tema',
 | 
			
		||||
                show_dependencies: 'Mostrar Dependências',
 | 
			
		||||
                hide_dependencies: 'Ocultar Dependências',
 | 
			
		||||
@@ -75,13 +64,22 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Organizar Diagrama Automaticamente',
 | 
			
		||||
            title: 'Reordenar Diagrama',
 | 
			
		||||
            description:
 | 
			
		||||
                'Esta ação reorganizará todas as tabelas no diagrama. Deseja continuar?',
 | 
			
		||||
            reorder: 'Organizar Automaticamente',
 | 
			
		||||
            reorder: 'Reordenar',
 | 
			
		||||
            cancel: 'Cancelar',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Múltiplos Esquemas',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} esquemas neste diagrama. Atualmente exibindo: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'nenhum',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Falha na cópia',
 | 
			
		||||
@@ -116,11 +114,14 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
        copied: 'Copiado!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Esquema:',
 | 
			
		||||
            filter_by_schema: 'Filtrar por esquema',
 | 
			
		||||
            search_schema: 'Buscar esquema...',
 | 
			
		||||
            no_schemas_found: 'Nenhum esquema encontrado.',
 | 
			
		||||
            view_all_options: 'Ver todas as Opções...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Tabelas',
 | 
			
		||||
                add_table: 'Adicionar Tabela',
 | 
			
		||||
                add_view: 'Adicionar Visualização',
 | 
			
		||||
                filter: 'Filtrar',
 | 
			
		||||
                collapse: 'Colapsar Todas',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -146,7 +147,6 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Atributos do Campo',
 | 
			
		||||
                        unique: 'Único',
 | 
			
		||||
                        auto_increment: 'Incremento Automático',
 | 
			
		||||
                        comments: 'Comentários',
 | 
			
		||||
                        no_comments: 'Sem comentários',
 | 
			
		||||
                        delete_field: 'Excluir Campo',
 | 
			
		||||
@@ -155,14 +155,11 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Precisão',
 | 
			
		||||
                        scale: 'Escala',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'Atributos do Índice',
 | 
			
		||||
                        name: 'Nome',
 | 
			
		||||
                        unique: 'Único',
 | 
			
		||||
                        index_type: 'Tipo de Índice',
 | 
			
		||||
                        delete_index: 'Excluir Índice',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -179,15 +176,12 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
                    description: 'Crie uma tabela para começar',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Filtrar',
 | 
			
		||||
                collapse: 'Colapsar Todas',
 | 
			
		||||
                add_relationship: 'Adicionar Relacionamento',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Relacionamentos',
 | 
			
		||||
                dependencies: 'Dependências',
 | 
			
		||||
                filter: 'Filtrar',
 | 
			
		||||
                add_relationship: 'Adicionar Relacionamento',
 | 
			
		||||
                collapse: 'Colapsar Todas',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Relacionamento',
 | 
			
		||||
                    primary: 'Tabela Primária',
 | 
			
		||||
                    foreign: 'Tabela Referenciada',
 | 
			
		||||
                    cardinality: 'Cardinalidade',
 | 
			
		||||
@@ -197,8 +191,16 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'Excluir',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Sem relacionamentos',
 | 
			
		||||
                    description: 'Crie um relacionamento para conectar tabelas',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Dependências',
 | 
			
		||||
                filter: 'Filtrar',
 | 
			
		||||
                collapse: 'Colapsar Todas',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Dependência',
 | 
			
		||||
                    table: 'Tabela',
 | 
			
		||||
                    dependent_table: 'Visualização Dependente',
 | 
			
		||||
                    delete_dependency: 'Excluir',
 | 
			
		||||
@@ -208,8 +210,8 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Sem relacionamentos',
 | 
			
		||||
                    description: 'Crie um relacionamento para começar',
 | 
			
		||||
                    title: 'Sem dependências',
 | 
			
		||||
                    description: 'Crie uma visualização para começar',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -233,35 +235,6 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuais',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Notas',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Filtrar',
 | 
			
		||||
                add_note: 'Adicionar Nota',
 | 
			
		||||
                no_results: 'Nenhuma nota encontrada',
 | 
			
		||||
                clear: 'Limpar Filtro',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Sem Notas',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Crie uma nota para adicionar anotações de texto na tela',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Nota vazia',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Ações de Nota',
 | 
			
		||||
                        edit_content: 'Editar Conteúdo',
 | 
			
		||||
                        delete_note: 'Excluir Nota',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -278,16 +251,12 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'Nenhum valor de enum definido',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -301,11 +270,7 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Mostrar Tudo',
 | 
			
		||||
            undo: 'Desfazer',
 | 
			
		||||
            redo: 'Refazer',
 | 
			
		||||
            reorder_diagram: 'Organizar Diagrama Automaticamente',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Reordenar Diagrama',
 | 
			
		||||
            highlight_overlapping_tables: 'Destacar Tabelas Sobrepostas',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -340,13 +305,13 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
            back: 'Voltar',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            empty_diagram: 'Banco de dados vazio',
 | 
			
		||||
            empty_diagram: 'Diagrama vazio',
 | 
			
		||||
            continue: 'Continuar',
 | 
			
		||||
            import: 'Importar',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Abrir Banco de Dados',
 | 
			
		||||
            title: 'Abrir Diagrama',
 | 
			
		||||
            description: 'Selecione um diagrama para abrir da lista abaixo.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'Nome',
 | 
			
		||||
@@ -356,12 +321,6 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Cancelar',
 | 
			
		||||
            open: 'Abrir',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Abrir',
 | 
			
		||||
                duplicate: 'Duplicar',
 | 
			
		||||
                delete: 'Excluir',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -448,14 +407,6 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
            confirm: 'Alterar',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Criar Novo Esquema',
 | 
			
		||||
            description:
 | 
			
		||||
                'Ainda não existem esquemas. Crie seu primeiro esquema para organizar suas tabelas.',
 | 
			
		||||
            create: 'Criar',
 | 
			
		||||
            cancel: 'Cancelar',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Ajude-nos a melhorar!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -511,11 +462,9 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Nova Tabela',
 | 
			
		||||
            new_view: 'Nova Visualização',
 | 
			
		||||
            new_relationship: 'Novo Relacionamento',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'Nova Nota',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -535,9 +484,6 @@ export const pt_BR: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Idioma',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Ligado',
 | 
			
		||||
        off: 'Desligado',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const ru: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Новая',
 | 
			
		||||
            browse: 'Обзор',
 | 
			
		||||
            tables: 'Таблицы',
 | 
			
		||||
            refs: 'Ссылки',
 | 
			
		||||
            dependencies: 'Зависимости',
 | 
			
		||||
            custom_types: 'Пользовательские типы',
 | 
			
		||||
            visuals: 'Визуальные элементы',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Действия',
 | 
			
		||||
                new: 'Новая...',
 | 
			
		||||
                browse: 'Обзор...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Файл',
 | 
			
		||||
                new: 'Создать',
 | 
			
		||||
                open: 'Открыть',
 | 
			
		||||
                save: 'Сохранить',
 | 
			
		||||
                import: 'Импортировать базу данных',
 | 
			
		||||
                export_sql: 'Экспорт SQL',
 | 
			
		||||
                export_as: 'Экспортировать как',
 | 
			
		||||
                delete_diagram: 'Удалить',
 | 
			
		||||
                delete_diagram: 'Удалить диаграмму',
 | 
			
		||||
                exit: 'Выход',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Изменение',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'Скрыть боковую панель',
 | 
			
		||||
                hide_cardinality: 'Скрыть виды связи',
 | 
			
		||||
                show_cardinality: 'Показать виды связи',
 | 
			
		||||
                show_field_attributes: 'Показать атрибуты поля',
 | 
			
		||||
                hide_field_attributes: 'Скрыть атрибуты поля',
 | 
			
		||||
                zoom_on_scroll: 'Увеличение при прокрутке',
 | 
			
		||||
                show_views: 'Представления базы данных',
 | 
			
		||||
                theme: 'Тема',
 | 
			
		||||
                show_dependencies: 'Показать зависимости',
 | 
			
		||||
                hide_dependencies: 'Скрыть зависимости',
 | 
			
		||||
@@ -73,13 +62,22 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Автоматическая расстановка диаграммы',
 | 
			
		||||
            title: 'Переупорядочить диаграмму',
 | 
			
		||||
            description:
 | 
			
		||||
                'Это действие переставит все таблицы на диаграмме. Хотите продолжить?',
 | 
			
		||||
            reorder: 'Автоматическая расстановка',
 | 
			
		||||
            reorder: 'Изменить порядок',
 | 
			
		||||
            cancel: 'Отменить',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Множественные схемы',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} схем в этой диаграмме. В данный момент отображается: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'никто',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Ошибка копирования',
 | 
			
		||||
@@ -113,11 +111,14 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
        show_less: 'Показать меньше',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Схема:',
 | 
			
		||||
            filter_by_schema: 'Фильтр по схеме',
 | 
			
		||||
            search_schema: 'Схема поиска...',
 | 
			
		||||
            no_schemas_found: 'Схемы не найдены.',
 | 
			
		||||
            view_all_options: 'Просмотреть все варианты...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Таблицы',
 | 
			
		||||
                add_table: 'Добавить таблицу',
 | 
			
		||||
                add_view: 'Добавить представление',
 | 
			
		||||
                filter: 'Фильтр',
 | 
			
		||||
                collapse: 'Свернуть все',
 | 
			
		||||
                clear: 'Очистить фильтр',
 | 
			
		||||
@@ -143,7 +144,6 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Атрибуты поля',
 | 
			
		||||
                        unique: 'Уникальный',
 | 
			
		||||
                        auto_increment: 'Автоинкремент',
 | 
			
		||||
                        comments: 'Комментарии',
 | 
			
		||||
                        no_comments: 'Нет комментария',
 | 
			
		||||
                        delete_field: 'Удалить поле',
 | 
			
		||||
@@ -151,14 +151,11 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
                        default_value: 'Default Value',
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        character_length: 'Макс. длина',
 | 
			
		||||
                        precision: 'Точность',
 | 
			
		||||
                        scale: 'Масштаб',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'Атрибуты индекса',
 | 
			
		||||
                        name: 'Имя',
 | 
			
		||||
                        unique: 'Уникальный',
 | 
			
		||||
                        index_type: 'Тип индекса',
 | 
			
		||||
                        delete_index: 'Удалить индекс',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -175,15 +172,12 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
                    description: 'Создайте таблицу, чтобы начать',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Ссылки',
 | 
			
		||||
                filter: 'Фильтр',
 | 
			
		||||
                collapse: 'Свернуть все',
 | 
			
		||||
                add_relationship: 'Добавить отношение',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Отношения',
 | 
			
		||||
                dependencies: 'Зависимости',
 | 
			
		||||
                filter: 'Фильтр',
 | 
			
		||||
                add_relationship: 'Добавить отношение',
 | 
			
		||||
                collapse: 'Свернуть все',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Отношение',
 | 
			
		||||
                    primary: 'Основная таблица',
 | 
			
		||||
                    foreign: 'Справочная таблица',
 | 
			
		||||
                    cardinality: 'Тип множественной связи',
 | 
			
		||||
@@ -193,10 +187,18 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'Удалить',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Нет отношений',
 | 
			
		||||
                    description: 'Создайте связь для соединения таблиц',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Зависимости',
 | 
			
		||||
                filter: 'Фильтр',
 | 
			
		||||
                collapse: 'Свернуть все',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Зависимость',
 | 
			
		||||
                    table: 'Таблица',
 | 
			
		||||
                    dependent_table: 'Зависимое представление',
 | 
			
		||||
                    table: 'Стол',
 | 
			
		||||
                    dependent_table: 'Зависимый вид',
 | 
			
		||||
                    delete_dependency: 'Удалить',
 | 
			
		||||
                    dependency_actions: {
 | 
			
		||||
                        title: 'Действия',
 | 
			
		||||
@@ -204,8 +206,8 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Нет отношений',
 | 
			
		||||
                    description: 'Создайте отношение, чтобы начать',
 | 
			
		||||
                    title: 'Нет зависимостей',
 | 
			
		||||
                    description: 'Создайте представление, чтобы начать',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -230,35 +232,6 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
                    description: 'Создайте область, чтобы начать',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Визуальные элементы',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Области',
 | 
			
		||||
                    notes: 'Заметки',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Фильтр',
 | 
			
		||||
                add_note: 'Добавить Заметку',
 | 
			
		||||
                no_results: 'Заметки не найдены',
 | 
			
		||||
                clear: 'Очистить Фильтр',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Нет Заметок',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Создайте заметку, чтобы добавить текстовые аннотации на холсте',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Пустая заметка',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Действия с Заметкой',
 | 
			
		||||
                        edit_content: 'Редактировать Содержимое',
 | 
			
		||||
                        delete_note: 'Удалить Заметку',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -275,16 +248,12 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'Значения перечисления не определены',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -298,11 +267,7 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Показать все',
 | 
			
		||||
            undo: 'Отменить',
 | 
			
		||||
            redo: 'Вернуть',
 | 
			
		||||
            reorder_diagram: 'Автоматическая расстановка диаграммы',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Переупорядочить диаграмму',
 | 
			
		||||
            highlight_overlapping_tables: 'Выделение перекрывающихся таблиц',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -336,13 +301,13 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
            cancel: 'Отменить',
 | 
			
		||||
            back: 'Назад',
 | 
			
		||||
            import_from_file: 'Импортировать из файла',
 | 
			
		||||
            empty_diagram: 'Пустая база данных',
 | 
			
		||||
            empty_diagram: 'Пустая диаграмма',
 | 
			
		||||
            continue: 'Продолжить',
 | 
			
		||||
            import: 'Импорт',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Открыть базу данных',
 | 
			
		||||
            title: 'Открыть диаграмму',
 | 
			
		||||
            description:
 | 
			
		||||
                'Выберите диаграмму, которую нужно открыть, из списка ниже.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
@@ -353,12 +318,6 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Отмена',
 | 
			
		||||
            open: 'Открыть',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Открыть',
 | 
			
		||||
                duplicate: 'Дублировать',
 | 
			
		||||
                delete: 'Удалить',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -445,14 +404,6 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
            confirm: 'Изменить',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Создать новую схему',
 | 
			
		||||
            description:
 | 
			
		||||
                'Схемы еще не существуют. Создайте вашу первую схему, чтобы организовать таблицы.',
 | 
			
		||||
            create: 'Создать',
 | 
			
		||||
            cancel: 'Отменить',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Помогите нам стать лучше!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -507,10 +458,8 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Создать таблицу',
 | 
			
		||||
            new_view: 'Новое представление',
 | 
			
		||||
            new_relationship: 'Создать отношение',
 | 
			
		||||
            new_area: 'Новая область',
 | 
			
		||||
            new_note: 'Новая Заметка',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -530,9 +479,6 @@ export const ru: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Сменить язык',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Вкл',
 | 
			
		||||
        off: 'Выкл',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const te: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'కొత్తది',
 | 
			
		||||
            browse: 'బ్రాఉజ్',
 | 
			
		||||
            tables: 'టేబల్లు',
 | 
			
		||||
            refs: 'సంబంధాలు',
 | 
			
		||||
            dependencies: 'ఆధారతలు',
 | 
			
		||||
            custom_types: 'కస్టమ్ టైప్స్',
 | 
			
		||||
            visuals: 'Visuals',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'చర్యలు',
 | 
			
		||||
                new: 'కొత్తది...',
 | 
			
		||||
                browse: 'బ్రాఉజ్ చేయండి...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'ఫైల్',
 | 
			
		||||
                new: 'కొత్తది',
 | 
			
		||||
                open: 'తెరవు',
 | 
			
		||||
                save: 'సేవ్',
 | 
			
		||||
                import: 'డేటాబేస్ను దిగుమతి చేసుకోండి',
 | 
			
		||||
                export_sql: 'SQL ఎగుమతి',
 | 
			
		||||
                export_as: 'వగా ఎగుమతి చేయండి',
 | 
			
		||||
                delete_diagram: 'తొలగించండి',
 | 
			
		||||
                delete_diagram: 'చిత్రాన్ని తొలగించండి',
 | 
			
		||||
                exit: 'నిష్క్రమించు',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'సవరించు',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const te: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'సైడ్బార్ దాచండి',
 | 
			
		||||
                hide_cardinality: 'కార్డినాలిటీని దాచండి',
 | 
			
		||||
                show_cardinality: 'కార్డినాలిటీని చూపించండి',
 | 
			
		||||
                show_field_attributes: 'ఫీల్డ్ గుణాలను చూపించు',
 | 
			
		||||
                hide_field_attributes: 'ఫీల్డ్ గుణాలను దాచండి',
 | 
			
		||||
                zoom_on_scroll: 'స్క్రోల్పై జూమ్',
 | 
			
		||||
                show_views: 'డేటాబేస్ వ్యూలు',
 | 
			
		||||
                theme: 'థీమ్',
 | 
			
		||||
                show_dependencies: 'ఆధారాలు చూపించండి',
 | 
			
		||||
                hide_dependencies: 'ఆధారాలను దాచండి',
 | 
			
		||||
@@ -75,13 +64,22 @@ export const te: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'చిత్రాన్ని స్వయంచాలకంగా అమర్చండి',
 | 
			
		||||
            title: 'చిత్రాన్ని పునఃసరిచేయండి',
 | 
			
		||||
            description:
 | 
			
		||||
                'ఈ చర్య చిత్రంలోని అన్ని పట్టికలను పునఃస్థాపిస్తుంది. మీరు కొనసాగించాలనుకుంటున్నారా?',
 | 
			
		||||
            reorder: 'స్వయంచాలకంగా అమర్చండి',
 | 
			
		||||
            reorder: 'పునఃసరిచేయండి',
 | 
			
		||||
            cancel: 'రద్దు',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'బహుళ స్కీమాలు',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} స్కీమాలు ఈ చిత్రంలో ఉన్నాయి. ప్రస్తుత స్కీమాలు: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'ఎదరికాదు',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'కాపీ విఫలమైంది',
 | 
			
		||||
@@ -116,11 +114,14 @@ export const te: LanguageTranslation = {
 | 
			
		||||
        copied: 'కాపీ చేయబడింది!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'స్కీమా:',
 | 
			
		||||
            filter_by_schema: 'స్కీమా ద్వారా ఫిల్టర్ చేయండి',
 | 
			
		||||
            search_schema: 'స్కీమా కోసం శోధించండి...',
 | 
			
		||||
            no_schemas_found: 'ఏ స్కీమాలు కూడా కనుగొనబడలేదు.',
 | 
			
		||||
            view_all_options: 'అన్ని ఎంపికలను చూడండి...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'పట్టికలు',
 | 
			
		||||
                add_table: 'పట్టికను జోడించు',
 | 
			
		||||
                add_view: 'వ్యూ జోడించండి',
 | 
			
		||||
                filter: 'ఫిల్టర్',
 | 
			
		||||
                collapse: 'అన్ని కూల్ చేయి',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -146,7 +147,6 @@ export const te: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'ఫీల్డ్ గుణాలు',
 | 
			
		||||
                        unique: 'అద్వితీయ',
 | 
			
		||||
                        auto_increment: 'ఆటో ఇంక్రిమెంట్',
 | 
			
		||||
                        comments: 'వ్యాఖ్యలు',
 | 
			
		||||
                        no_comments: 'వ్యాఖ్యలు లేవు',
 | 
			
		||||
                        delete_field: 'ఫీల్డ్ తొలగించు',
 | 
			
		||||
@@ -155,14 +155,11 @@ export const te: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'సూక్ష్మత',
 | 
			
		||||
                        scale: 'స్కేల్',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'ఇండెక్స్ గుణాలు',
 | 
			
		||||
                        name: 'పేరు',
 | 
			
		||||
                        unique: 'అద్వితీయ',
 | 
			
		||||
                        index_type: 'ఇండెక్స్ రకం',
 | 
			
		||||
                        delete_index: 'ఇండెక్స్ తొలగించు',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -180,15 +177,12 @@ export const te: LanguageTranslation = {
 | 
			
		||||
                    description: 'ప్రారంభించడానికి ఒక పట్టిక సృష్టించండి',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'ఫిల్టర్',
 | 
			
		||||
                collapse: 'అన్ని కూల్ చేయి',
 | 
			
		||||
                add_relationship: 'సంబంధం జోడించు',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'సంబంధాలు',
 | 
			
		||||
                dependencies: 'ఆధారాలు',
 | 
			
		||||
                filter: 'ఫిల్టర్',
 | 
			
		||||
                add_relationship: 'సంబంధం జోడించు',
 | 
			
		||||
                collapse: 'అన్ని కూల్ చేయి',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'సంబంధం',
 | 
			
		||||
                    primary: 'ప్రాథమిక పట్టిక',
 | 
			
		||||
                    foreign: 'సూచించబడిన పట్టిక',
 | 
			
		||||
                    cardinality: 'కార్డినాలిటీ',
 | 
			
		||||
@@ -198,8 +192,16 @@ export const te: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'సంబంధం తొలగించు',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'సంబంధాలు లేవు',
 | 
			
		||||
                    description: 'పట్టికలను అనుసంధించడానికి సంబంధం సృష్టించండి',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'ఆధారాలు',
 | 
			
		||||
                filter: 'ఫిల్టర్',
 | 
			
		||||
                collapse: 'అన్ని కూల్ చేయి',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'ఆధారం',
 | 
			
		||||
                    table: 'పట్టిక',
 | 
			
		||||
                    dependent_table: 'ఆధారిత వీక్షణ',
 | 
			
		||||
                    delete_dependency: 'ఆధారాన్ని తొలగించు',
 | 
			
		||||
@@ -209,8 +211,8 @@ export const te: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'సంబంధాలు లేవు',
 | 
			
		||||
                    description: 'ప్రారంభించడానికి ఒక సంబంధం సృష్టించండి',
 | 
			
		||||
                    title: 'ఆధారాలు లేవు',
 | 
			
		||||
                    description: 'ప్రారంభించడానికి ఒక వీక్షణ సృష్టించండి',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -234,35 +236,6 @@ export const te: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Visuals',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'గమనికలు',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'ఫిల్టర్',
 | 
			
		||||
                add_note: 'గమనిక జోడించండి',
 | 
			
		||||
                no_results: 'గమనికలు కనుగొనబడలేదు',
 | 
			
		||||
                clear: 'ఫిల్టర్ను క్లియర్ చేయండి',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'గమనికలు లేవు',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'కాన్వాస్పై టెక్స్ట్ ఉల్లేఖనలను జోడించడానికి ఒక గమనికను సృష్టించండి',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'ఖాళీ గమనిక',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'గమనిక చర్యలు',
 | 
			
		||||
                        edit_content: 'కంటెంట్ను సవరించండి',
 | 
			
		||||
                        delete_note: 'గమనికను తొలగించండి',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -279,16 +252,12 @@ export const te: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'ఏ enum విలువలు నిర్వచించబడలేదు',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -302,11 +271,7 @@ export const te: LanguageTranslation = {
 | 
			
		||||
            show_all: 'అన్ని చూపించు',
 | 
			
		||||
            undo: 'తిరిగి చేయు',
 | 
			
		||||
            redo: 'మరలా చేయు',
 | 
			
		||||
            reorder_diagram: 'చిత్రాన్ని స్వయంచాలకంగా అమర్చండి',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'చిత్రాన్ని పునఃసరిచేయండి',
 | 
			
		||||
            highlight_overlapping_tables: 'అవకాశించు పట్టికలను హైలైట్ చేయండి',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -341,13 +306,13 @@ export const te: LanguageTranslation = {
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            back: 'తిరుగు',
 | 
			
		||||
            empty_diagram: 'ఖాళీ డేటాబేస్',
 | 
			
		||||
            empty_diagram: 'ఖాళీ చిత్రము',
 | 
			
		||||
            continue: 'కొనసాగించు',
 | 
			
		||||
            import: 'డిగుమతి',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'డేటాబేస్ తెరవండి',
 | 
			
		||||
            title: 'చిత్రం తెరవండి',
 | 
			
		||||
            description: 'కింద ఉన్న జాబితా నుండి చిత్రాన్ని ఎంచుకోండి.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'పేరు',
 | 
			
		||||
@@ -357,12 +322,6 @@ export const te: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'రద్దు',
 | 
			
		||||
            open: 'తెరవు',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'తెరవు',
 | 
			
		||||
                duplicate: 'నకలు',
 | 
			
		||||
                delete: 'తొలగించు',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -449,14 +408,6 @@ export const te: LanguageTranslation = {
 | 
			
		||||
            confirm: 'మార్చు',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'కొత్త స్కీమా సృష్టించండి',
 | 
			
		||||
            description:
 | 
			
		||||
                'ఇంకా ఏ స్కీమాలు లేవు. మీ పట్టికలను వ్యవస్థీకరించడానికి మీ మొదటి స్కీమాను సృష్టించండి.',
 | 
			
		||||
            create: 'సృష్టించు',
 | 
			
		||||
            cancel: 'రద్దు',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'మా సహాయంతో మెరుగుపరచండి!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -515,11 +466,9 @@ export const te: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'కొత్త పట్టిక',
 | 
			
		||||
            new_view: 'కొత్త వ్యూ',
 | 
			
		||||
            new_relationship: 'కొత్త సంబంధం',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'కొత్త నోట్',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -540,9 +489,6 @@ export const te: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'భాష మార్చు',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'ఆన్',
 | 
			
		||||
        off: 'ఆఫ్',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const tr: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Yeni',
 | 
			
		||||
            browse: 'Gözat',
 | 
			
		||||
            tables: 'Tablolar',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Bağımlılıklar',
 | 
			
		||||
            custom_types: 'Özel Tipler',
 | 
			
		||||
            visuals: 'Görseller',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Eylemler',
 | 
			
		||||
                new: 'Yeni...',
 | 
			
		||||
                browse: 'Gözat...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Dosya',
 | 
			
		||||
                new: 'Yeni',
 | 
			
		||||
                open: 'Aç',
 | 
			
		||||
                save: 'Kaydet',
 | 
			
		||||
                import: 'Veritabanı İçe Aktar',
 | 
			
		||||
                export_sql: 'SQL Olarak Dışa Aktar',
 | 
			
		||||
                export_as: 'Olarak Dışa Aktar',
 | 
			
		||||
                delete_diagram: 'Sil',
 | 
			
		||||
                delete_diagram: 'Diyagramı Sil',
 | 
			
		||||
                exit: 'Çıkış',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Düzenle',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'Kenar Çubuğunu Gizle',
 | 
			
		||||
                hide_cardinality: 'Kardinaliteyi Gizle',
 | 
			
		||||
                show_cardinality: 'Kardinaliteyi Göster',
 | 
			
		||||
                show_field_attributes: 'Alan Özelliklerini Göster',
 | 
			
		||||
                hide_field_attributes: 'Alan Özelliklerini Gizle',
 | 
			
		||||
                zoom_on_scroll: 'Kaydırarak Yakınlaştır',
 | 
			
		||||
                show_views: 'Veritabanı Görünümleri',
 | 
			
		||||
                theme: 'Tema',
 | 
			
		||||
                show_dependencies: 'Bağımlılıkları Göster',
 | 
			
		||||
                hide_dependencies: 'Bağımlılıkları Gizle',
 | 
			
		||||
@@ -75,13 +64,22 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Diyagramı Otomatik Düzenle',
 | 
			
		||||
            title: 'Diyagramı Yeniden Sırala',
 | 
			
		||||
            description:
 | 
			
		||||
                'Bu işlem tüm tabloları yeniden düzenleyecektir. Devam etmek istiyor musunuz?',
 | 
			
		||||
            reorder: 'Otomatik Düzenle',
 | 
			
		||||
            reorder: 'Yeniden Sırala',
 | 
			
		||||
            cancel: 'İptal',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Birden Fazla Şema',
 | 
			
		||||
            description:
 | 
			
		||||
                'Bu diyagramda {{schemasCount}} şema var. Şu anda görüntülenen: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'yok',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Kopyalama başarısız',
 | 
			
		||||
@@ -115,11 +113,14 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
        copy_to_clipboard: 'Panoya Kopyala',
 | 
			
		||||
        copied: 'Kopyalandı!',
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Şema:',
 | 
			
		||||
            filter_by_schema: 'Şemaya Göre Filtrele',
 | 
			
		||||
            search_schema: 'Şema ara...',
 | 
			
		||||
            no_schemas_found: 'Şema bulunamadı.',
 | 
			
		||||
            view_all_options: 'Tüm Seçenekleri Gör...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Tablolar',
 | 
			
		||||
                add_table: 'Tablo Ekle',
 | 
			
		||||
                add_view: 'Görünüm Ekle',
 | 
			
		||||
                filter: 'Filtrele',
 | 
			
		||||
                collapse: 'Hepsini Daralt',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -145,7 +146,6 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Alan Özellikleri',
 | 
			
		||||
                        unique: 'Tekil',
 | 
			
		||||
                        auto_increment: 'Otomatik Artış',
 | 
			
		||||
                        comments: 'Yorumlar',
 | 
			
		||||
                        no_comments: 'Yorum yok',
 | 
			
		||||
                        delete_field: 'Alanı Sil',
 | 
			
		||||
@@ -154,14 +154,11 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Hassasiyet',
 | 
			
		||||
                        scale: 'Ölçek',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'İndeks Özellikleri',
 | 
			
		||||
                        name: 'Ad',
 | 
			
		||||
                        unique: 'Tekil',
 | 
			
		||||
                        index_type: 'İndeks Türü',
 | 
			
		||||
                        delete_index: 'İndeksi Sil',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -179,15 +176,12 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
                    description: 'Başlamak için bir tablo oluşturun',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Filtrele',
 | 
			
		||||
                collapse: 'Hepsini Daralt',
 | 
			
		||||
                add_relationship: 'İlişki Ekle',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'İlişkiler',
 | 
			
		||||
                dependencies: 'Bağımlılıklar',
 | 
			
		||||
                filter: 'Filtrele',
 | 
			
		||||
                add_relationship: 'İlişki Ekle',
 | 
			
		||||
                collapse: 'Hepsini Daralt',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'İlişki',
 | 
			
		||||
                    primary: 'Birincil Tablo',
 | 
			
		||||
                    foreign: 'Referans Tablo',
 | 
			
		||||
                    cardinality: 'Kardinalite',
 | 
			
		||||
@@ -197,8 +191,16 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'Sil',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'İlişki yok',
 | 
			
		||||
                    description: 'Tabloları bağlamak için bir ilişki oluşturun',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Bağımlılıklar',
 | 
			
		||||
                filter: 'Filtrele',
 | 
			
		||||
                collapse: 'Hepsini Daralt',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Bağımlılık',
 | 
			
		||||
                    table: 'Tablo',
 | 
			
		||||
                    dependent_table: 'Bağımlı Görünüm',
 | 
			
		||||
                    delete_dependency: 'Sil',
 | 
			
		||||
@@ -208,8 +210,8 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'İlişki yok',
 | 
			
		||||
                    description: 'Başlamak için bir ilişki oluşturun',
 | 
			
		||||
                    title: 'Bağımlılık yok',
 | 
			
		||||
                    description: 'Başlamak için bir görünüm oluşturun',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -233,35 +235,6 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Görseller',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Notlar',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Filtrele',
 | 
			
		||||
                add_note: 'Not Ekle',
 | 
			
		||||
                no_results: 'Not bulunamadı',
 | 
			
		||||
                clear: 'Filtreyi Temizle',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Not Yok',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Tuval üzerinde metin açıklamaları eklemek için bir not oluşturun',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Boş not',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Not İşlemleri',
 | 
			
		||||
                        edit_content: 'İçeriği Düzenle',
 | 
			
		||||
                        delete_note: 'Notu Sil',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -278,16 +251,12 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'Tanımlanmış enum değeri yok',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -300,11 +269,7 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Hepsini Gör',
 | 
			
		||||
            undo: 'Geri Al',
 | 
			
		||||
            redo: 'Yinele',
 | 
			
		||||
            reorder_diagram: 'Diyagramı Otomatik Düzenle',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Diyagramı Yeniden Sırala',
 | 
			
		||||
            highlight_overlapping_tables: 'Çakışan Tabloları Vurgula',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -337,12 +302,12 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
            import_from_file: 'Import from File',
 | 
			
		||||
            cancel: 'İptal',
 | 
			
		||||
            back: 'Geri',
 | 
			
		||||
            empty_diagram: 'Boş veritabanı',
 | 
			
		||||
            empty_diagram: 'Boş diyagram',
 | 
			
		||||
            continue: 'Devam',
 | 
			
		||||
            import: 'İçe Aktar',
 | 
			
		||||
        },
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Veritabanı Aç',
 | 
			
		||||
            title: 'Diyagramı Aç',
 | 
			
		||||
            description: 'Aşağıdaki listeden açmak için bir diyagram seçin.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'Ad',
 | 
			
		||||
@@ -352,12 +317,6 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'İptal',
 | 
			
		||||
            open: 'Aç',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Aç',
 | 
			
		||||
                duplicate: 'Kopyala',
 | 
			
		||||
                delete: 'Sil',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -438,14 +397,6 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
            cancel: 'İptal',
 | 
			
		||||
            confirm: 'Değiştir',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Yeni Şema Oluştur',
 | 
			
		||||
            description:
 | 
			
		||||
                'Henüz hiç şema mevcut değil. Tablolarınızı düzenlemek için ilk şemanızı oluşturun.',
 | 
			
		||||
            create: 'Oluştur',
 | 
			
		||||
            cancel: 'İptal',
 | 
			
		||||
        },
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Bize yardım et!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -500,11 +451,9 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Yeni Tablo',
 | 
			
		||||
            new_view: 'Yeni Görünüm',
 | 
			
		||||
            new_relationship: 'Yeni İlişki',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'Yeni Not',
 | 
			
		||||
        },
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
            edit_table: 'Tabloyu Düzenle',
 | 
			
		||||
@@ -524,9 +473,6 @@ export const tr: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Dil',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Açık',
 | 
			
		||||
        off: 'Kapalı',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const uk: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Нова',
 | 
			
		||||
            browse: 'Огляд',
 | 
			
		||||
            tables: 'Таблиці',
 | 
			
		||||
            refs: 'Зв’язки',
 | 
			
		||||
            dependencies: 'Залежності',
 | 
			
		||||
            custom_types: 'Користувацькі типи',
 | 
			
		||||
            visuals: 'Візуальні елементи',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Дії',
 | 
			
		||||
                new: 'Нова...',
 | 
			
		||||
                browse: 'Огляд...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Файл',
 | 
			
		||||
                new: 'Новий',
 | 
			
		||||
                open: 'Відкрити',
 | 
			
		||||
                save: 'Зберегти',
 | 
			
		||||
                import: 'Імпорт бази даних',
 | 
			
		||||
                export_sql: 'Експорт SQL',
 | 
			
		||||
                export_as: 'Експортувати як',
 | 
			
		||||
                delete_diagram: 'Видалити',
 | 
			
		||||
                delete_diagram: 'Видалити діаграму',
 | 
			
		||||
                exit: 'Вийти',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Редагувати',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'Приховати бічну панель',
 | 
			
		||||
                hide_cardinality: 'Приховати потужність',
 | 
			
		||||
                show_cardinality: 'Показати кардинальність',
 | 
			
		||||
                show_field_attributes: 'Показати атрибути полів',
 | 
			
		||||
                hide_field_attributes: 'Приховати атрибути полів',
 | 
			
		||||
                zoom_on_scroll: 'Масштабувати прокручуванням',
 | 
			
		||||
                show_views: 'Представлення бази даних',
 | 
			
		||||
                theme: 'Тема',
 | 
			
		||||
                show_dependencies: 'Показати залежності',
 | 
			
		||||
                hide_dependencies: 'Приховати залежності',
 | 
			
		||||
@@ -73,13 +62,22 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Автоматичне розміщення діаграми',
 | 
			
		||||
            title: 'Перевпорядкувати діаграму',
 | 
			
		||||
            description:
 | 
			
		||||
                'Ця дія перевпорядкує всі таблиці на діаграмі. Хочете продовжити?',
 | 
			
		||||
            reorder: 'Автоматичне розміщення',
 | 
			
		||||
            reorder: 'Перевпорядкувати',
 | 
			
		||||
            cancel: 'Скасувати',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Кілька схем',
 | 
			
		||||
            description:
 | 
			
		||||
                '{{schemasCount}} схеми на цій діаграмі. Зараз відображається: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'немає',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Помилка копіювання',
 | 
			
		||||
@@ -114,11 +112,14 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
        copied: 'Скопійовано!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Схема:',
 | 
			
		||||
            filter_by_schema: 'Фільтрувати за схемою',
 | 
			
		||||
            search_schema: 'Пошук схеми…',
 | 
			
		||||
            no_schemas_found: 'Схеми не знайдено.',
 | 
			
		||||
            view_all_options: 'Переглянути всі параметри…',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Таблиці',
 | 
			
		||||
                add_table: 'Додати таблицю',
 | 
			
		||||
                add_view: 'Додати представлення',
 | 
			
		||||
                filter: 'Фільтр',
 | 
			
		||||
                collapse: 'Згорнути все',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -144,7 +145,6 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Атрибути полів',
 | 
			
		||||
                        unique: 'Унікальне',
 | 
			
		||||
                        auto_increment: 'Автоінкремент',
 | 
			
		||||
                        comments: 'Коментарі',
 | 
			
		||||
                        no_comments: 'Немає коментарів',
 | 
			
		||||
                        delete_field: 'Видалити поле',
 | 
			
		||||
@@ -153,14 +153,11 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Точність',
 | 
			
		||||
                        scale: 'Масштаб',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'Атрибути індексу',
 | 
			
		||||
                        name: 'Назва індекса',
 | 
			
		||||
                        unique: 'Унікальний',
 | 
			
		||||
                        index_type: 'Тип індексу',
 | 
			
		||||
                        delete_index: 'Видалити індекс',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -177,15 +174,12 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
                    description: 'Щоб почати, створіть таблицю',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Фільтр',
 | 
			
		||||
                collapse: 'Згорнути все',
 | 
			
		||||
                add_relationship: 'Додати звʼязок',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Звʼязки',
 | 
			
		||||
                dependencies: 'Залежності',
 | 
			
		||||
                filter: 'Фільтр',
 | 
			
		||||
                add_relationship: 'Додати звʼязок',
 | 
			
		||||
                collapse: 'Згорнути все',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Звʼязок',
 | 
			
		||||
                    primary: 'Первинна таблиця',
 | 
			
		||||
                    foreign: 'Посилання на таблицю',
 | 
			
		||||
                    cardinality: 'Звʼязок',
 | 
			
		||||
@@ -195,8 +189,16 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'Видалити',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Звʼязків немає',
 | 
			
		||||
                    description: 'Створіть звʼязок для зʼєднання таблиць',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Залежності',
 | 
			
		||||
                filter: 'Фільтр',
 | 
			
		||||
                collapse: 'Згорнути все',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Залежність',
 | 
			
		||||
                    table: 'Таблиця',
 | 
			
		||||
                    dependent_table: 'Залежне подання',
 | 
			
		||||
                    delete_dependency: 'Видалити',
 | 
			
		||||
@@ -206,8 +208,8 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Жодних зв’язків',
 | 
			
		||||
                    description: 'Створіть зв’язок, щоб почати',
 | 
			
		||||
                    title: 'Жодних залежностей',
 | 
			
		||||
                    description: 'Створіть подання, щоб почати',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -231,35 +233,6 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Візуальні елементи',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Нотатки',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Фільтр',
 | 
			
		||||
                add_note: 'Додати Нотатку',
 | 
			
		||||
                no_results: 'Нотатки не знайдено',
 | 
			
		||||
                clear: 'Очистити Фільтр',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Немає Нотаток',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Створіть нотатку, щоб додати текстові анотації на полотні',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Порожня нотатка',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Дії з Нотаткою',
 | 
			
		||||
                        edit_content: 'Редагувати Вміст',
 | 
			
		||||
                        delete_note: 'Видалити Нотатку',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -276,16 +249,12 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'Значення переліку не визначені',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -299,11 +268,7 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Показати все',
 | 
			
		||||
            undo: 'Скасувати',
 | 
			
		||||
            redo: 'Повторити',
 | 
			
		||||
            reorder_diagram: 'Автоматичне розміщення діаграми',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Перевпорядкувати діаграму',
 | 
			
		||||
            highlight_overlapping_tables: 'Показати таблиці, що перекриваються',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -337,13 +302,13 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
            cancel: 'Скасувати',
 | 
			
		||||
            back: 'Назад',
 | 
			
		||||
            import_from_file: 'Імпортувати з файлу',
 | 
			
		||||
            empty_diagram: 'Порожня база даних',
 | 
			
		||||
            empty_diagram: 'Порожня діаграма',
 | 
			
		||||
            continue: 'Продовжити',
 | 
			
		||||
            import: 'Імпорт',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Відкрити базу даних',
 | 
			
		||||
            title: 'Відкрити діаграму',
 | 
			
		||||
            description:
 | 
			
		||||
                'Виберіть діаграму, яку потрібно відкрити, зі списку нижче.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
@@ -354,12 +319,6 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Скасувати',
 | 
			
		||||
            open: 'Відкрити',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Відкрити',
 | 
			
		||||
                duplicate: 'Дублювати',
 | 
			
		||||
                delete: 'Видалити',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -446,14 +405,6 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
            confirm: 'Змінити',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Створити нову схему',
 | 
			
		||||
            description:
 | 
			
		||||
                'Поки що не існує жодної схеми. Створіть свою першу схему, щоб організувати ваші таблиці.',
 | 
			
		||||
            create: 'Створити',
 | 
			
		||||
            cancel: 'Скасувати',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Допоможіть нам покращитися!',
 | 
			
		||||
            description: 'Поставне на зірку на GitHub? Це лише один клік!',
 | 
			
		||||
@@ -506,11 +457,9 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Нова таблиця',
 | 
			
		||||
            new_view: 'Нове представлення',
 | 
			
		||||
            new_relationship: 'Новий звʼязок',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'Нова Нотатка',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -529,9 +478,6 @@ export const uk: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Мова',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Увімк',
 | 
			
		||||
        off: 'Вимк',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const vi: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: 'Mới',
 | 
			
		||||
            browse: 'Duyệt',
 | 
			
		||||
            tables: 'Bảng',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: 'Phụ thuộc',
 | 
			
		||||
            custom_types: 'Kiểu tùy chỉnh',
 | 
			
		||||
            visuals: 'Hình ảnh',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: 'Hành động',
 | 
			
		||||
                new: 'Mới...',
 | 
			
		||||
                browse: 'Duyệt...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: 'Tệp',
 | 
			
		||||
                new: 'Tạo mới',
 | 
			
		||||
                open: 'Mở',
 | 
			
		||||
                save: 'Lưu',
 | 
			
		||||
                import: 'Nhập cơ sở dữ liệu',
 | 
			
		||||
                export_sql: 'Xuất SQL',
 | 
			
		||||
                export_as: 'Xuất thành',
 | 
			
		||||
                delete_diagram: 'Xóa',
 | 
			
		||||
                delete_diagram: 'Xóa sơ đồ',
 | 
			
		||||
                exit: 'Thoát',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: 'Sửa',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: 'Ẩn thanh bên',
 | 
			
		||||
                hide_cardinality: 'Ẩn số lượng',
 | 
			
		||||
                show_cardinality: 'Hiển thị số lượng',
 | 
			
		||||
                show_field_attributes: 'Hiển thị thuộc tính trường',
 | 
			
		||||
                hide_field_attributes: 'Ẩn thuộc tính trường',
 | 
			
		||||
                zoom_on_scroll: 'Thu phóng khi cuộn',
 | 
			
		||||
                show_views: 'Chế độ xem Cơ sở dữ liệu',
 | 
			
		||||
                theme: 'Chủ đề',
 | 
			
		||||
                show_dependencies: 'Hiển thị các phụ thuộc',
 | 
			
		||||
                hide_dependencies: 'Ẩn các phụ thuộc',
 | 
			
		||||
@@ -74,13 +63,22 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: 'Tự động sắp xếp sơ đồ',
 | 
			
		||||
            title: 'Sắp xếp lại sơ đồ',
 | 
			
		||||
            description:
 | 
			
		||||
                'Hành động này sẽ sắp xếp lại tất cả các bảng trong sơ đồ. Bạn có muốn tiếp tục không?',
 | 
			
		||||
            reorder: 'Tự động sắp xếp',
 | 
			
		||||
            reorder: 'Sắp xếp',
 | 
			
		||||
            cancel: 'Hủy',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: 'Có nhiều lược đồ',
 | 
			
		||||
            description:
 | 
			
		||||
                'Có {{schemasCount}} lược đồ trong sơ đồ này. Hiện đang hiển thị: {{formattedSchemas}}.',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: 'không có',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: 'Sao chép thất bại',
 | 
			
		||||
@@ -115,11 +113,14 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
        copied: 'Đã sao chép!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Lược đồ:',
 | 
			
		||||
            filter_by_schema: 'Lọc bởi lược đồ',
 | 
			
		||||
            search_schema: 'Tìm kiếm lược đồ...',
 | 
			
		||||
            no_schemas_found: 'Không tìm thấy lược đồ.',
 | 
			
		||||
            view_all_options: 'Xem tất cả tùy chọn...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: 'Bảng',
 | 
			
		||||
                add_table: 'Thêm bảng',
 | 
			
		||||
                add_view: 'Thêm Chế độ xem',
 | 
			
		||||
                filter: 'Lọc',
 | 
			
		||||
                collapse: 'Thu gọn tất cả',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -145,7 +146,6 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: 'Thuộc tính trường',
 | 
			
		||||
                        unique: 'Giá trị duy nhất',
 | 
			
		||||
                        auto_increment: 'Tự động tăng',
 | 
			
		||||
                        comments: 'Bình luận',
 | 
			
		||||
                        no_comments: 'Không có bình luận',
 | 
			
		||||
                        delete_field: 'Xóa trường',
 | 
			
		||||
@@ -154,14 +154,11 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: 'Độ chính xác',
 | 
			
		||||
                        scale: 'Tỷ lệ',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: 'Thuộc tính chỉ mục',
 | 
			
		||||
                        name: 'Tên',
 | 
			
		||||
                        unique: 'Giá trị duy nhất',
 | 
			
		||||
                        index_type: 'Loại chỉ mục',
 | 
			
		||||
                        delete_index: 'Xóa chỉ mục',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -178,15 +175,12 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
                    description: 'Tạo một bảng để bắt đầu',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: 'Lọc',
 | 
			
		||||
                collapse: 'Thu gọn tất cả',
 | 
			
		||||
                add_relationship: 'Thêm quan hệ',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: 'Quan hệ',
 | 
			
		||||
                dependencies: 'Phụ thuộc',
 | 
			
		||||
                filter: 'Lọc',
 | 
			
		||||
                add_relationship: 'Thêm quan hệ',
 | 
			
		||||
                collapse: 'Thu gọn tất cả',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: 'Quan hệ',
 | 
			
		||||
                    primary: 'Bảng khóa chính',
 | 
			
		||||
                    foreign: 'Bảng khóa ngoại',
 | 
			
		||||
                    cardinality: 'Quan hệ',
 | 
			
		||||
@@ -196,8 +190,16 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: 'Xóa',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Không có quan hệ',
 | 
			
		||||
                    description: 'Tạo quan hệ để kết nối các bảng',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: 'Phụ thuộc',
 | 
			
		||||
                filter: 'Lọc',
 | 
			
		||||
                collapse: 'Thu gọn tất cả',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: 'Phụ thuộc',
 | 
			
		||||
                    table: 'Bảng',
 | 
			
		||||
                    dependent_table: 'Bảng xem phụ thuộc',
 | 
			
		||||
                    delete_dependency: 'Xóa',
 | 
			
		||||
@@ -207,8 +209,8 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Không có quan hệ',
 | 
			
		||||
                    description: 'Tạo một quan hệ để bắt đầu',
 | 
			
		||||
                    title: 'Không có phụ thuộc',
 | 
			
		||||
                    description: 'Tạo bảng xem phụ thuộc để bắt đầu',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -232,35 +234,6 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: 'Hình ảnh',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: 'Ghi chú',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: 'Lọc',
 | 
			
		||||
                add_note: 'Thêm Ghi Chú',
 | 
			
		||||
                no_results: 'Không tìm thấy ghi chú',
 | 
			
		||||
                clear: 'Xóa Bộ Lọc',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: 'Không Có Ghi Chú',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'Tạo ghi chú để thêm chú thích văn bản trên canvas',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: 'Ghi chú trống',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: 'Hành Động Ghi Chú',
 | 
			
		||||
                        edit_content: 'Chỉnh Sửa Nội Dung',
 | 
			
		||||
                        delete_note: 'Xóa Ghi Chú',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -277,16 +250,12 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: 'Không có giá trị enum được định nghĩa',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -300,11 +269,7 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
            show_all: 'Hiển thị tất cả',
 | 
			
		||||
            undo: 'Hoàn tác',
 | 
			
		||||
            redo: 'Làm lại',
 | 
			
		||||
            reorder_diagram: 'Tự động sắp xếp sơ đồ',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: 'Sắp xếp lại sơ đồ',
 | 
			
		||||
            highlight_overlapping_tables: 'Làm nổi bật các bảng chồng chéo',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -338,13 +303,13 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
            cancel: 'Hủy',
 | 
			
		||||
            import_from_file: 'Nhập từ tệp',
 | 
			
		||||
            back: 'Trở lại',
 | 
			
		||||
            empty_diagram: 'Cơ sở dữ liệu trống',
 | 
			
		||||
            empty_diagram: 'Sơ đồ trống',
 | 
			
		||||
            continue: 'Tiếp tục',
 | 
			
		||||
            import: 'Nhập',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: 'Mở cơ sở dữ liệu',
 | 
			
		||||
            title: 'Mở sơ đồ',
 | 
			
		||||
            description: 'Chọn sơ đồ để mở từ danh sách bên dưới.',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: 'Tên',
 | 
			
		||||
@@ -354,12 +319,6 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: 'Hủy',
 | 
			
		||||
            open: 'Mở',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: 'Mở',
 | 
			
		||||
                duplicate: 'Nhân bản',
 | 
			
		||||
                delete: 'Xóa',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -445,14 +404,6 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
            confirm: 'Xác nhận',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: 'Tạo lược đồ mới',
 | 
			
		||||
            description:
 | 
			
		||||
                'Chưa có lược đồ nào. Tạo lược đồ đầu tiên của bạn để tổ chức các bảng.',
 | 
			
		||||
            create: 'Tạo',
 | 
			
		||||
            cancel: 'Hủy',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: 'Hãy giúp chúng tôi cải thiện!',
 | 
			
		||||
            description:
 | 
			
		||||
@@ -507,11 +458,9 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: 'Tạo bảng mới',
 | 
			
		||||
            new_view: 'Chế độ xem Mới',
 | 
			
		||||
            new_relationship: 'Tạo quan hệ mới',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: 'Ghi Chú Mới',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -530,9 +479,6 @@ export const vi: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: 'Ngôn ngữ',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: 'Bật',
 | 
			
		||||
        off: 'Tắt',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const zh_CN: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: '新建',
 | 
			
		||||
            browse: '浏览',
 | 
			
		||||
            tables: '表',
 | 
			
		||||
            refs: '引用',
 | 
			
		||||
            dependencies: '依赖关系',
 | 
			
		||||
            custom_types: '自定义类型',
 | 
			
		||||
            visuals: '视觉效果',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: '操作',
 | 
			
		||||
                new: '新建...',
 | 
			
		||||
                browse: '浏览...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: '文件',
 | 
			
		||||
                new: '新建',
 | 
			
		||||
                open: '打开',
 | 
			
		||||
                save: '保存',
 | 
			
		||||
                import: '导入数据库',
 | 
			
		||||
                export_sql: '导出 SQL 语句',
 | 
			
		||||
                export_as: '导出为',
 | 
			
		||||
                delete_diagram: '删除',
 | 
			
		||||
                delete_diagram: '删除关系图',
 | 
			
		||||
                exit: '退出',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: '编辑',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: '隐藏侧边栏',
 | 
			
		||||
                hide_cardinality: '隐藏基数',
 | 
			
		||||
                show_cardinality: '展示基数',
 | 
			
		||||
                show_field_attributes: '展示字段属性',
 | 
			
		||||
                hide_field_attributes: '隐藏字段属性',
 | 
			
		||||
                zoom_on_scroll: '滚动缩放',
 | 
			
		||||
                show_views: '数据库视图',
 | 
			
		||||
                theme: '主题',
 | 
			
		||||
                show_dependencies: '展示依赖',
 | 
			
		||||
                hide_dependencies: '隐藏依赖',
 | 
			
		||||
@@ -72,12 +61,21 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: '自动排列关系图',
 | 
			
		||||
            title: '重新排列关系图',
 | 
			
		||||
            description: '此操作将重新排列关系图中的所有表。是否要继续?',
 | 
			
		||||
            reorder: '自动排列',
 | 
			
		||||
            reorder: '重新排列',
 | 
			
		||||
            cancel: '取消',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: '多个模式',
 | 
			
		||||
            description:
 | 
			
		||||
                '此关系图中有 {{schemasCount}} 个模式,当前显示:{{formattedSchemas}}。',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: '无',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: '复制失败',
 | 
			
		||||
@@ -112,11 +110,14 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
        copied: '复制了!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: '模式:',
 | 
			
		||||
            filter_by_schema: '按模式筛选',
 | 
			
		||||
            search_schema: '搜索模式...',
 | 
			
		||||
            no_schemas_found: '未找到模式。',
 | 
			
		||||
            view_all_options: '查看所有选项...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: '表',
 | 
			
		||||
                add_table: '添加表',
 | 
			
		||||
                add_view: '添加视图',
 | 
			
		||||
                filter: '筛选',
 | 
			
		||||
                collapse: '全部折叠',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -142,7 +143,6 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: '字段属性',
 | 
			
		||||
                        unique: '唯一',
 | 
			
		||||
                        auto_increment: '自动递增',
 | 
			
		||||
                        comments: '注释',
 | 
			
		||||
                        no_comments: '空',
 | 
			
		||||
                        delete_field: '删除字段',
 | 
			
		||||
@@ -151,14 +151,11 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: '精度',
 | 
			
		||||
                        scale: '小数位',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: '索引属性',
 | 
			
		||||
                        name: '名称',
 | 
			
		||||
                        unique: '唯一',
 | 
			
		||||
                        index_type: '索引类型',
 | 
			
		||||
                        delete_index: '删除索引',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -175,15 +172,12 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
                    description: '新建表以开始',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: '引用',
 | 
			
		||||
                filter: '筛选',
 | 
			
		||||
                collapse: '全部折叠',
 | 
			
		||||
                add_relationship: '添加关系',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: '关系',
 | 
			
		||||
                dependencies: '依赖关系',
 | 
			
		||||
                filter: '筛选',
 | 
			
		||||
                add_relationship: '添加关系',
 | 
			
		||||
                collapse: '全部折叠',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: '关系',
 | 
			
		||||
                    primary: '主表',
 | 
			
		||||
                    foreign: '被引用表',
 | 
			
		||||
                    cardinality: '基数',
 | 
			
		||||
@@ -193,8 +187,16 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: '删除',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '无关系',
 | 
			
		||||
                    description: '创建关系以连接表',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: '依赖关系',
 | 
			
		||||
                filter: '筛选',
 | 
			
		||||
                collapse: '全部折叠',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: '依赖',
 | 
			
		||||
                    table: '表',
 | 
			
		||||
                    dependent_table: '依赖视图',
 | 
			
		||||
                    delete_dependency: '删除',
 | 
			
		||||
@@ -204,8 +206,8 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '无关系',
 | 
			
		||||
                    description: '创建关系以开始',
 | 
			
		||||
                    title: '无依赖',
 | 
			
		||||
                    description: '创建视图以开始',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -229,34 +231,6 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: '视觉效果',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: '笔记',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: '筛选',
 | 
			
		||||
                add_note: '添加笔记',
 | 
			
		||||
                no_results: '未找到笔记',
 | 
			
		||||
                clear: '清除筛选',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '没有笔记',
 | 
			
		||||
                    description: '创建笔记以在画布上添加文本注释',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: '空笔记',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: '笔记操作',
 | 
			
		||||
                        edit_content: '编辑内容',
 | 
			
		||||
                        delete_note: '删除笔记',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -273,16 +247,12 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: '没有定义枚举值',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -296,11 +266,7 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
            show_all: '展示全部',
 | 
			
		||||
            undo: '撤销',
 | 
			
		||||
            redo: '重做',
 | 
			
		||||
            reorder_diagram: '自动排列关系图',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: '重新排列关系图',
 | 
			
		||||
            highlight_overlapping_tables: '突出显示重叠的表',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -334,13 +300,13 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
            cancel: '取消',
 | 
			
		||||
            import_from_file: '从文件导入',
 | 
			
		||||
            back: '上一步',
 | 
			
		||||
            empty_diagram: '空数据库',
 | 
			
		||||
            empty_diagram: '新建空关系图',
 | 
			
		||||
            continue: '下一步',
 | 
			
		||||
            import: '导入',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: '打开数据库',
 | 
			
		||||
            title: '打开关系图',
 | 
			
		||||
            description: '从下面的列表中选择一个图表打开。',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: '名称',
 | 
			
		||||
@@ -350,12 +316,6 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: '取消',
 | 
			
		||||
            open: '打开',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: '打开',
 | 
			
		||||
                duplicate: '复制',
 | 
			
		||||
                delete: '删除',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -440,13 +400,6 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
            confirm: '更改',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: '创建新模式',
 | 
			
		||||
            description: '尚未存在任何模式。创建您的第一个模式来组织您的表。',
 | 
			
		||||
            create: '创建',
 | 
			
		||||
            cancel: '取消',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: '帮助我们改进!',
 | 
			
		||||
            description: '您想在 GitHub 上为我们加注星标吗?只需点击一下即可!',
 | 
			
		||||
@@ -501,11 +454,9 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: '新建表',
 | 
			
		||||
            new_view: '新建视图',
 | 
			
		||||
            new_relationship: '新建关系',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: '新笔记',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -524,9 +475,6 @@ export const zh_CN: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: '语言',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: '开启',
 | 
			
		||||
        off: '关闭',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,25 +2,17 @@ import type { LanguageMetadata, LanguageTranslation } from '../types';
 | 
			
		||||
 | 
			
		||||
export const zh_TW: LanguageTranslation = {
 | 
			
		||||
    translation: {
 | 
			
		||||
        editor_sidebar: {
 | 
			
		||||
            new_diagram: '新建',
 | 
			
		||||
            browse: '瀏覽',
 | 
			
		||||
            tables: '表格',
 | 
			
		||||
            refs: 'Refs',
 | 
			
		||||
            dependencies: '相依性',
 | 
			
		||||
            custom_types: '自定義類型',
 | 
			
		||||
            visuals: '視覺效果',
 | 
			
		||||
        },
 | 
			
		||||
        menu: {
 | 
			
		||||
            actions: {
 | 
			
		||||
                actions: '操作',
 | 
			
		||||
                new: '新增...',
 | 
			
		||||
                browse: '瀏覽...',
 | 
			
		||||
            file: {
 | 
			
		||||
                file: '檔案',
 | 
			
		||||
                new: '新增',
 | 
			
		||||
                open: '開啟',
 | 
			
		||||
                save: '儲存',
 | 
			
		||||
                import: '匯入資料庫',
 | 
			
		||||
                export_sql: '匯出 SQL',
 | 
			
		||||
                export_as: '匯出為特定格式',
 | 
			
		||||
                delete_diagram: '刪除',
 | 
			
		||||
                delete_diagram: '刪除圖表',
 | 
			
		||||
                exit: '退出',
 | 
			
		||||
            },
 | 
			
		||||
            edit: {
 | 
			
		||||
                edit: '編輯',
 | 
			
		||||
@@ -34,10 +26,7 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
                hide_sidebar: '隱藏側邊欄',
 | 
			
		||||
                hide_cardinality: '隱藏基數',
 | 
			
		||||
                show_cardinality: '顯示基數',
 | 
			
		||||
                hide_field_attributes: '隱藏欄位屬性',
 | 
			
		||||
                show_field_attributes: '顯示欄位屬性',
 | 
			
		||||
                zoom_on_scroll: '滾動縮放',
 | 
			
		||||
                show_views: '資料庫檢視',
 | 
			
		||||
                theme: '主題',
 | 
			
		||||
                show_dependencies: '顯示相依性',
 | 
			
		||||
                hide_dependencies: '隱藏相依性',
 | 
			
		||||
@@ -72,12 +61,21 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        reorder_diagram_alert: {
 | 
			
		||||
            title: '自動排列圖表',
 | 
			
		||||
            title: '重新排列圖表',
 | 
			
		||||
            description: '此操作將重新排列圖表中的所有表格。是否繼續?',
 | 
			
		||||
            reorder: '自動排列',
 | 
			
		||||
            reorder: '重新排列',
 | 
			
		||||
            cancel: '取消',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        multiple_schemas_alert: {
 | 
			
		||||
            title: '多重 Schema',
 | 
			
		||||
            description:
 | 
			
		||||
                '此圖表中包含 {{schemasCount}} 個 Schema,目前顯示:{{formattedSchemas}}。',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            show_me: 'Show me',
 | 
			
		||||
            none: '無',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        copy_to_clipboard_toast: {
 | 
			
		||||
            unsupported: {
 | 
			
		||||
                title: '複製失敗',
 | 
			
		||||
@@ -112,11 +110,14 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
        copied: '已複製!',
 | 
			
		||||
 | 
			
		||||
        side_panel: {
 | 
			
		||||
            schema: 'Schema:',
 | 
			
		||||
            filter_by_schema: '依 Schema 篩選',
 | 
			
		||||
            search_schema: '搜尋 Schema...',
 | 
			
		||||
            no_schemas_found: '未找到 Schema。',
 | 
			
		||||
            view_all_options: '顯示所有選項...',
 | 
			
		||||
            tables_section: {
 | 
			
		||||
                tables: '表格',
 | 
			
		||||
                add_table: '新增表格',
 | 
			
		||||
                add_view: '新增檢視',
 | 
			
		||||
                filter: '篩選',
 | 
			
		||||
                collapse: '全部摺疊',
 | 
			
		||||
                // TODO: Translate
 | 
			
		||||
@@ -142,7 +143,6 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
                    field_actions: {
 | 
			
		||||
                        title: '欄位屬性',
 | 
			
		||||
                        unique: '唯一',
 | 
			
		||||
                        auto_increment: '自動遞增',
 | 
			
		||||
                        comments: '註解',
 | 
			
		||||
                        no_comments: '無註解',
 | 
			
		||||
                        delete_field: '刪除欄位',
 | 
			
		||||
@@ -151,14 +151,11 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
                        no_default: 'No default',
 | 
			
		||||
                        // TODO: Translate
 | 
			
		||||
                        character_length: 'Max Length',
 | 
			
		||||
                        precision: '精度',
 | 
			
		||||
                        scale: '小數位',
 | 
			
		||||
                    },
 | 
			
		||||
                    index_actions: {
 | 
			
		||||
                        title: '索引屬性',
 | 
			
		||||
                        name: '名稱',
 | 
			
		||||
                        unique: '唯一',
 | 
			
		||||
                        index_type: '索引類型',
 | 
			
		||||
                        delete_index: '刪除索引',
 | 
			
		||||
                    },
 | 
			
		||||
                    table_actions: {
 | 
			
		||||
@@ -175,15 +172,12 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
                    description: '請新增表格以開始',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            refs_section: {
 | 
			
		||||
                refs: 'Refs',
 | 
			
		||||
                filter: '篩選',
 | 
			
		||||
                collapse: '全部摺疊',
 | 
			
		||||
                add_relationship: '新增關聯',
 | 
			
		||||
            relationships_section: {
 | 
			
		||||
                relationships: '關聯',
 | 
			
		||||
                dependencies: '相依性',
 | 
			
		||||
                filter: '篩選',
 | 
			
		||||
                add_relationship: '新增關聯',
 | 
			
		||||
                collapse: '全部摺疊',
 | 
			
		||||
                relationship: {
 | 
			
		||||
                    relationship: '關聯',
 | 
			
		||||
                    primary: '主表格',
 | 
			
		||||
                    foreign: '參照表格',
 | 
			
		||||
                    cardinality: '基數',
 | 
			
		||||
@@ -193,8 +187,16 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
                        delete_relationship: '刪除',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '尚無關聯',
 | 
			
		||||
                    description: '請新增關聯以連接表格',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            dependencies_section: {
 | 
			
		||||
                dependencies: '相依性',
 | 
			
		||||
                filter: '篩選',
 | 
			
		||||
                collapse: '全部摺疊',
 | 
			
		||||
                dependency: {
 | 
			
		||||
                    dependency: '相依性',
 | 
			
		||||
                    table: '表格',
 | 
			
		||||
                    dependent_table: '相依檢視',
 | 
			
		||||
                    delete_dependency: '刪除',
 | 
			
		||||
@@ -204,8 +206,8 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '尚無關聯',
 | 
			
		||||
                    description: '請建立關聯以開始',
 | 
			
		||||
                    title: '尚無相依性',
 | 
			
		||||
                    description: '請建立檢視以開始',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
@@ -229,34 +231,6 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
                    description: 'Create an area to get started',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            visuals_section: {
 | 
			
		||||
                visuals: '視覺效果',
 | 
			
		||||
                tabs: {
 | 
			
		||||
                    areas: 'Areas',
 | 
			
		||||
                    notes: '筆記',
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            notes_section: {
 | 
			
		||||
                filter: '篩選',
 | 
			
		||||
                add_note: '新增筆記',
 | 
			
		||||
                no_results: '未找到筆記',
 | 
			
		||||
                clear: '清除篩選',
 | 
			
		||||
                empty_state: {
 | 
			
		||||
                    title: '沒有筆記',
 | 
			
		||||
                    description: '建立筆記以在畫布上新增文字註解',
 | 
			
		||||
                },
 | 
			
		||||
                note: {
 | 
			
		||||
                    empty_note: '空白筆記',
 | 
			
		||||
                    note_actions: {
 | 
			
		||||
                        title: '筆記操作',
 | 
			
		||||
                        edit_content: '編輯內容',
 | 
			
		||||
                        delete_note: '刪除筆記',
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            custom_types_section: {
 | 
			
		||||
                custom_types: 'Custom Types',
 | 
			
		||||
@@ -273,16 +247,12 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
                    enum_values: 'Enum Values',
 | 
			
		||||
                    composite_fields: 'Fields',
 | 
			
		||||
                    no_fields: 'No fields defined',
 | 
			
		||||
                    no_values: '沒有定義列舉值',
 | 
			
		||||
                    field_name_placeholder: 'Field name',
 | 
			
		||||
                    field_type_placeholder: 'Select type',
 | 
			
		||||
                    add_field: 'Add Field',
 | 
			
		||||
                    no_fields_tooltip: 'No fields defined for this custom type',
 | 
			
		||||
                    custom_type_actions: {
 | 
			
		||||
                        title: 'Actions',
 | 
			
		||||
                        highlight_fields: 'Highlight Fields',
 | 
			
		||||
                        delete_custom_type: 'Delete',
 | 
			
		||||
                        clear_field_highlight: 'Clear Highlight',
 | 
			
		||||
                    },
 | 
			
		||||
                    delete_custom_type: 'Delete Type',
 | 
			
		||||
                },
 | 
			
		||||
@@ -296,11 +266,7 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
            show_all: '顯示全部',
 | 
			
		||||
            undo: '復原',
 | 
			
		||||
            redo: '重做',
 | 
			
		||||
            reorder_diagram: '自動排列圖表',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            clear_custom_type_highlight: 'Clear highlight for "{{typeName}}"',
 | 
			
		||||
            custom_type_highlight_tooltip:
 | 
			
		||||
                'Highlighting "{{typeName}}" - Click to clear',
 | 
			
		||||
            reorder_diagram: '重新排列圖表',
 | 
			
		||||
            highlight_overlapping_tables: '突出顯示重疊表格',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            filter: 'Filter Tables',
 | 
			
		||||
@@ -333,13 +299,13 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
            cancel: '取消',
 | 
			
		||||
            import_from_file: '從檔案匯入',
 | 
			
		||||
            back: '返回',
 | 
			
		||||
            empty_diagram: '空資料庫',
 | 
			
		||||
            empty_diagram: '空白圖表',
 | 
			
		||||
            continue: '繼續',
 | 
			
		||||
            import: '匯入',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        open_diagram_dialog: {
 | 
			
		||||
            title: '開啟資料庫',
 | 
			
		||||
            title: '開啟圖表',
 | 
			
		||||
            description: '請從以下列表中選擇一個圖表。',
 | 
			
		||||
            table_columns: {
 | 
			
		||||
                name: '名稱',
 | 
			
		||||
@@ -349,12 +315,6 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
            },
 | 
			
		||||
            cancel: '取消',
 | 
			
		||||
            open: '開啟',
 | 
			
		||||
 | 
			
		||||
            diagram_actions: {
 | 
			
		||||
                open: '開啟',
 | 
			
		||||
                duplicate: '複製',
 | 
			
		||||
                delete: '刪除',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        export_sql_dialog: {
 | 
			
		||||
@@ -439,14 +399,6 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
            confirm: '變更',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        create_table_schema_dialog: {
 | 
			
		||||
            title: '建立新 Schema',
 | 
			
		||||
            description:
 | 
			
		||||
                '尚未存在任何 Schema。建立您的第一個 Schema 來組織您的表格。',
 | 
			
		||||
            create: '建立',
 | 
			
		||||
            cancel: '取消',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        star_us_dialog: {
 | 
			
		||||
            title: '協助我們改善!',
 | 
			
		||||
            description: '請在 GitHub 上給我們一顆星,只需點擊一下!',
 | 
			
		||||
@@ -501,11 +453,9 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
 | 
			
		||||
        canvas_context_menu: {
 | 
			
		||||
            new_table: '新建表格',
 | 
			
		||||
            new_view: '新檢視',
 | 
			
		||||
            new_relationship: '新建關聯',
 | 
			
		||||
            // TODO: Translate
 | 
			
		||||
            new_area: 'New Area',
 | 
			
		||||
            new_note: '新筆記',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        table_node_context_menu: {
 | 
			
		||||
@@ -524,9 +474,6 @@ export const zh_TW: LanguageTranslation = {
 | 
			
		||||
        language_select: {
 | 
			
		||||
            change_language: '變更語言',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        on: '開啟',
 | 
			
		||||
        off: '關閉',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,4 @@
 | 
			
		||||
 | 
			
		||||
    .marker-definitions {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .nodrag {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import type { DBCustomType } from './domain';
 | 
			
		||||
import type { Area } from './domain/area';
 | 
			
		||||
import type { DBDependency } from './domain/db-dependency';
 | 
			
		||||
import type { DBField } from './domain/db-field';
 | 
			
		||||
@@ -6,7 +5,6 @@ import type { DBIndex } from './domain/db-index';
 | 
			
		||||
import type { DBRelationship } from './domain/db-relationship';
 | 
			
		||||
import type { DBTable } from './domain/db-table';
 | 
			
		||||
import type { Diagram } from './domain/diagram';
 | 
			
		||||
import type { Note } from './domain/note';
 | 
			
		||||
import { generateId as defaultGenerateId } from './utils';
 | 
			
		||||
 | 
			
		||||
const generateIdsMapFromTable = (
 | 
			
		||||
@@ -50,14 +48,6 @@ const generateIdsMapFromDiagram = (
 | 
			
		||||
        idsMap.set(area.id, generateId());
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    diagram.notes?.forEach((note) => {
 | 
			
		||||
        idsMap.set(note.id, generateId());
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    diagram.customTypes?.forEach((customType) => {
 | 
			
		||||
        idsMap.set(customType.id, generateId());
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return idsMap;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -223,37 +213,6 @@ export const cloneDiagram = (
 | 
			
		||||
            })
 | 
			
		||||
            .filter((area): area is Area => area !== null) ?? [];
 | 
			
		||||
 | 
			
		||||
    const notes: Note[] =
 | 
			
		||||
        diagram.notes
 | 
			
		||||
            ?.map((note) => {
 | 
			
		||||
                const id = getNewId(note.id);
 | 
			
		||||
                if (!id) {
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    ...note,
 | 
			
		||||
                    id,
 | 
			
		||||
                } satisfies Note;
 | 
			
		||||
            })
 | 
			
		||||
            .filter((note): note is Note => note !== null) ?? [];
 | 
			
		||||
 | 
			
		||||
    const customTypes: DBCustomType[] =
 | 
			
		||||
        diagram.customTypes
 | 
			
		||||
            ?.map((customType) => {
 | 
			
		||||
                const id = getNewId(customType.id);
 | 
			
		||||
                if (!id) {
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
                return {
 | 
			
		||||
                    ...customType,
 | 
			
		||||
                    id,
 | 
			
		||||
                } satisfies DBCustomType;
 | 
			
		||||
            })
 | 
			
		||||
            .filter(
 | 
			
		||||
                (customType): customType is DBCustomType => customType !== null
 | 
			
		||||
            ) ?? [];
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        diagram: {
 | 
			
		||||
            ...diagram,
 | 
			
		||||
@@ -262,8 +221,6 @@ export const cloneDiagram = (
 | 
			
		||||
            relationships,
 | 
			
		||||
            tables,
 | 
			
		||||
            areas,
 | 
			
		||||
            notes,
 | 
			
		||||
            customTypes,
 | 
			
		||||
            createdAt: diagram.createdAt
 | 
			
		||||
                ? new Date(diagram.createdAt)
 | 
			
		||||
                : new Date(),
 | 
			
		||||
 
 | 
			
		||||
@@ -19,5 +19,3 @@ export const randomColor = () => {
 | 
			
		||||
 | 
			
		||||
export const viewColor = '#b0b0b0';
 | 
			
		||||
export const materializedViewColor = '#7d7d7d';
 | 
			
		||||
export const defaultTableColor = '#8eb7ff';
 | 
			
		||||
export const defaultAreaColor = '#b067e9';
 | 
			
		||||
 
 | 
			
		||||
@@ -48,30 +48,18 @@ export const clickhouseDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    { name: 'mediumblob', id: 'mediumblob' },
 | 
			
		||||
    { name: 'tinyblob', id: 'tinyblob' },
 | 
			
		||||
    { name: 'blob', id: 'blob' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varchar',
 | 
			
		||||
        id: 'varchar',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'char', id: 'char', fieldAttributes: { hasCharMaxLength: true } },
 | 
			
		||||
    { name: 'varchar', id: 'varchar', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'char', id: 'char', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'char large object', id: 'char_large_object' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'char varying',
 | 
			
		||||
        id: 'char_varying',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'char varying', id: 'char_varying', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'character large object', id: 'character_large_object' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'character varying',
 | 
			
		||||
        id: 'character_varying',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        hasCharMaxLength: true,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'nchar large object', id: 'nchar_large_object' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'nchar varying',
 | 
			
		||||
        id: 'nchar_varying',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'nchar varying', id: 'nchar_varying', hasCharMaxLength: true },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'national character large object',
 | 
			
		||||
        id: 'national_character_large_object',
 | 
			
		||||
@@ -79,34 +67,22 @@ export const clickhouseDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    {
 | 
			
		||||
        name: 'national character varying',
 | 
			
		||||
        id: 'national_character_varying',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        hasCharMaxLength: true,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'national char varying',
 | 
			
		||||
        id: 'national_char_varying',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        hasCharMaxLength: true,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'national character',
 | 
			
		||||
        id: 'national_character',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'national char',
 | 
			
		||||
        id: 'national_char',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        hasCharMaxLength: true,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'national char', id: 'national_char', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'binary large object', id: 'binary_large_object' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'binary varying',
 | 
			
		||||
        id: 'binary_varying',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'fixedstring',
 | 
			
		||||
        id: 'fixedstring',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'binary varying', id: 'binary_varying', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'fixedstring', id: 'fixedstring', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'string', id: 'string' },
 | 
			
		||||
 | 
			
		||||
    // Date Types
 | 
			
		||||
@@ -129,6 +105,9 @@ export const clickhouseDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    { name: 'enum', id: 'enum' },
 | 
			
		||||
    { name: 'lowcardinality', id: 'lowcardinality' },
 | 
			
		||||
 | 
			
		||||
    // Array Type
 | 
			
		||||
    { name: 'array', id: 'array' },
 | 
			
		||||
 | 
			
		||||
    // Tuple Type
 | 
			
		||||
    { name: 'tuple', id: 'tuple' },
 | 
			
		||||
    { name: 'map', id: 'map' },
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
import { z } from 'zod';
 | 
			
		||||
import { DatabaseType } from '../../domain/database-type';
 | 
			
		||||
import { databaseSupportsArrays } from '../../domain/database-capabilities';
 | 
			
		||||
import { clickhouseDataTypes } from './clickhouse-data-types';
 | 
			
		||||
import { genericDataTypes } from './generic-data-types';
 | 
			
		||||
import { mariadbDataTypes } from './mariadb-data-types';
 | 
			
		||||
@@ -15,23 +14,9 @@ export interface DataType {
 | 
			
		||||
    name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FieldAttributeRange {
 | 
			
		||||
    max: number;
 | 
			
		||||
    min: number;
 | 
			
		||||
    default: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface FieldAttributes {
 | 
			
		||||
    hasCharMaxLength?: boolean;
 | 
			
		||||
    hasCharMaxLengthOption?: boolean;
 | 
			
		||||
    precision?: FieldAttributeRange;
 | 
			
		||||
    scale?: FieldAttributeRange;
 | 
			
		||||
    maxLength?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DataTypeData extends DataType {
 | 
			
		||||
    hasCharMaxLength?: boolean;
 | 
			
		||||
    usageLevel?: 1 | 2; // Level 1 is most common, Level 2 is second most common
 | 
			
		||||
    fieldAttributes?: FieldAttributes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const dataTypeSchema: z.ZodType<DataType> = z.object({
 | 
			
		||||
@@ -147,53 +132,3 @@ export const findDataTypeDataById = (
 | 
			
		||||
 | 
			
		||||
    return dataTypesOptions.find((dataType) => dataType.id === id);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const supportsAutoIncrementDataType = (
 | 
			
		||||
    dataTypeName: string
 | 
			
		||||
): boolean => {
 | 
			
		||||
    return [
 | 
			
		||||
        'integer',
 | 
			
		||||
        'int',
 | 
			
		||||
        'bigint',
 | 
			
		||||
        'smallint',
 | 
			
		||||
        'tinyint',
 | 
			
		||||
        'mediumint',
 | 
			
		||||
        'serial',
 | 
			
		||||
        'bigserial',
 | 
			
		||||
        'smallserial',
 | 
			
		||||
        'number',
 | 
			
		||||
        'numeric',
 | 
			
		||||
        'decimal',
 | 
			
		||||
    ].includes(dataTypeName.toLocaleLowerCase());
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const autoIncrementAlwaysOn = (dataTypeName: string): boolean => {
 | 
			
		||||
    return ['serial', 'bigserial', 'smallserial'].includes(
 | 
			
		||||
        dataTypeName.toLowerCase()
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const requiresNotNull = (dataTypeName: string): boolean => {
 | 
			
		||||
    return ['serial', 'bigserial', 'smallserial'].includes(
 | 
			
		||||
        dataTypeName.toLowerCase()
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ARRAY_INCOMPATIBLE_TYPES = [
 | 
			
		||||
    'serial',
 | 
			
		||||
    'bigserial',
 | 
			
		||||
    'smallserial',
 | 
			
		||||
] as const;
 | 
			
		||||
 | 
			
		||||
export const supportsArrayDataType = (
 | 
			
		||||
    dataTypeName: string,
 | 
			
		||||
    databaseType: DatabaseType
 | 
			
		||||
): boolean => {
 | 
			
		||||
    if (!databaseSupportsArrays(databaseType)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return !ARRAY_INCOMPATIBLE_TYPES.includes(
 | 
			
		||||
        dataTypeName.toLowerCase() as (typeof ARRAY_INCOMPATIBLE_TYPES)[number]
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,7 @@ import type { DataTypeData } from './data-types';
 | 
			
		||||
 | 
			
		||||
export const genericDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    // Level 1 - Most commonly used types
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varchar',
 | 
			
		||||
        id: 'varchar',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'varchar', id: 'varchar', hasCharMaxLength: true, usageLevel: 1 },
 | 
			
		||||
    { name: 'int', id: 'int', usageLevel: 1 },
 | 
			
		||||
    { name: 'text', id: 'text', usageLevel: 1 },
 | 
			
		||||
    { name: 'boolean', id: 'boolean', usageLevel: 1 },
 | 
			
		||||
@@ -15,62 +10,23 @@ export const genericDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    { name: 'timestamp', id: 'timestamp', usageLevel: 1 },
 | 
			
		||||
 | 
			
		||||
    // Level 2 - Second most common types
 | 
			
		||||
    {
 | 
			
		||||
        name: 'decimal',
 | 
			
		||||
        id: 'decimal',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 999,
 | 
			
		||||
                min: 1,
 | 
			
		||||
                default: 10,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 999,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 2,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'decimal', id: 'decimal', usageLevel: 2 },
 | 
			
		||||
    { name: 'datetime', id: 'datetime', usageLevel: 2 },
 | 
			
		||||
    { name: 'json', id: 'json', usageLevel: 2 },
 | 
			
		||||
    { name: 'uuid', id: 'uuid', usageLevel: 2 },
 | 
			
		||||
 | 
			
		||||
    // Less common types
 | 
			
		||||
    { name: 'bigint', id: 'bigint' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'binary',
 | 
			
		||||
        id: 'binary',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'binary', id: 'binary', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'blob', id: 'blob' },
 | 
			
		||||
    { name: 'char', id: 'char', fieldAttributes: { hasCharMaxLength: true } },
 | 
			
		||||
    { name: 'char', id: 'char', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'double', id: 'double' },
 | 
			
		||||
    { name: 'enum', id: 'enum' },
 | 
			
		||||
    { name: 'float', id: 'float' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'numeric',
 | 
			
		||||
        id: 'numeric',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 999,
 | 
			
		||||
                min: 1,
 | 
			
		||||
                default: 10,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 999,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 2,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'numeric', id: 'numeric' },
 | 
			
		||||
    { name: 'real', id: 'real' },
 | 
			
		||||
    { name: 'set', id: 'set' },
 | 
			
		||||
    { name: 'smallint', id: 'smallint' },
 | 
			
		||||
    { name: 'time', id: 'time' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varbinary',
 | 
			
		||||
        id: 'varbinary',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'varbinary', id: 'varbinary', hasCharMaxLength: true },
 | 
			
		||||
] as const;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,32 +4,12 @@ export const mariadbDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    // Level 1 - Most commonly used types
 | 
			
		||||
    { name: 'int', id: 'int', usageLevel: 1 },
 | 
			
		||||
    { name: 'bigint', id: 'bigint', usageLevel: 1 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'decimal',
 | 
			
		||||
        id: 'decimal',
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 65,
 | 
			
		||||
                min: 1,
 | 
			
		||||
                default: 10,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 30,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 0,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'decimal', id: 'decimal', usageLevel: 1 },
 | 
			
		||||
    { name: 'boolean', id: 'boolean', usageLevel: 1 },
 | 
			
		||||
    { name: 'datetime', id: 'datetime', usageLevel: 1 },
 | 
			
		||||
    { name: 'date', id: 'date', usageLevel: 1 },
 | 
			
		||||
    { name: 'timestamp', id: 'timestamp', usageLevel: 1 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varchar',
 | 
			
		||||
        id: 'varchar',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'varchar', id: 'varchar', hasCharMaxLength: true, usageLevel: 1 },
 | 
			
		||||
    { name: 'text', id: 'text', usageLevel: 1 },
 | 
			
		||||
 | 
			
		||||
    // Level 2 - Second most common types
 | 
			
		||||
@@ -40,39 +20,16 @@ export const mariadbDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    { name: 'tinyint', id: 'tinyint' },
 | 
			
		||||
    { name: 'smallint', id: 'smallint' },
 | 
			
		||||
    { name: 'mediumint', id: 'mediumint' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'numeric',
 | 
			
		||||
        id: 'numeric',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 65,
 | 
			
		||||
                min: 1,
 | 
			
		||||
                default: 10,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 30,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 0,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'numeric', id: 'numeric' },
 | 
			
		||||
    { name: 'float', id: 'float' },
 | 
			
		||||
    { name: 'double', id: 'double' },
 | 
			
		||||
    { name: 'bit', id: 'bit' },
 | 
			
		||||
    { name: 'bool', id: 'bool' },
 | 
			
		||||
    { name: 'time', id: 'time' },
 | 
			
		||||
    { name: 'year', id: 'year' },
 | 
			
		||||
    { name: 'char', id: 'char', fieldAttributes: { hasCharMaxLength: true } },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'binary',
 | 
			
		||||
        id: 'binary',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varbinary',
 | 
			
		||||
        id: 'varbinary',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'char', id: 'char', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'binary', id: 'binary', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'varbinary', id: 'varbinary', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'tinyblob', id: 'tinyblob' },
 | 
			
		||||
    { name: 'blob', id: 'blob' },
 | 
			
		||||
    { name: 'mediumblob', id: 'mediumblob' },
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,7 @@ import type { DataTypeData } from './data-types';
 | 
			
		||||
export const mysqlDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    // Level 1 - Most commonly used types
 | 
			
		||||
    { name: 'int', id: 'int', usageLevel: 1 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varchar',
 | 
			
		||||
        id: 'varchar',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'varchar', id: 'varchar', hasCharMaxLength: true, usageLevel: 1 },
 | 
			
		||||
    { name: 'text', id: 'text', usageLevel: 1 },
 | 
			
		||||
    { name: 'boolean', id: 'boolean', usageLevel: 1 },
 | 
			
		||||
    { name: 'timestamp', id: 'timestamp', usageLevel: 1 },
 | 
			
		||||
@@ -16,23 +11,7 @@ export const mysqlDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
 | 
			
		||||
    // Level 2 - Second most common types
 | 
			
		||||
    { name: 'bigint', id: 'bigint', usageLevel: 2 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'decimal',
 | 
			
		||||
        id: 'decimal',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 65,
 | 
			
		||||
                min: 1,
 | 
			
		||||
                default: 10,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 30,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 0,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'decimal', id: 'decimal', usageLevel: 2 },
 | 
			
		||||
    { name: 'datetime', id: 'datetime', usageLevel: 2 },
 | 
			
		||||
    { name: 'json', id: 'json', usageLevel: 2 },
 | 
			
		||||
 | 
			
		||||
@@ -43,7 +22,7 @@ export const mysqlDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    { name: 'float', id: 'float' },
 | 
			
		||||
    { name: 'double', id: 'double' },
 | 
			
		||||
    { name: 'bit', id: 'bit' },
 | 
			
		||||
    { name: 'char', id: 'char', fieldAttributes: { hasCharMaxLength: true } },
 | 
			
		||||
    { name: 'char', id: 'char', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'tinytext', id: 'tinytext' },
 | 
			
		||||
    { name: 'mediumtext', id: 'mediumtext' },
 | 
			
		||||
    { name: 'longtext', id: 'longtext' },
 | 
			
		||||
 
 | 
			
		||||
@@ -2,30 +2,15 @@ import type { DataTypeData } from './data-types';
 | 
			
		||||
 | 
			
		||||
export const oracleDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    // Character types
 | 
			
		||||
    {
 | 
			
		||||
        name: 'VARCHAR2',
 | 
			
		||||
        id: 'varchar2',
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'VARCHAR2', id: 'varchar2', usageLevel: 1, hasCharMaxLength: true },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'NVARCHAR2',
 | 
			
		||||
        id: 'nvarchar2',
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'CHAR',
 | 
			
		||||
        id: 'char',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'NCHAR',
 | 
			
		||||
        id: 'nchar',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        hasCharMaxLength: true,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'CHAR', id: 'char', usageLevel: 2, hasCharMaxLength: true },
 | 
			
		||||
    { name: 'NCHAR', id: 'nchar', usageLevel: 2, hasCharMaxLength: true },
 | 
			
		||||
    { name: 'CLOB', id: 'clob', usageLevel: 2 },
 | 
			
		||||
    { name: 'NCLOB', id: 'nclob', usageLevel: 2 },
 | 
			
		||||
 | 
			
		||||
@@ -64,12 +49,7 @@ export const oracleDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    { name: 'BFILE', id: 'bfile', usageLevel: 2 },
 | 
			
		||||
 | 
			
		||||
    // Other types
 | 
			
		||||
    {
 | 
			
		||||
        name: 'RAW',
 | 
			
		||||
        id: 'raw',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'RAW', id: 'raw', usageLevel: 2, hasCharMaxLength: true },
 | 
			
		||||
    { name: 'LONG RAW', id: 'long_raw', usageLevel: 2 },
 | 
			
		||||
    { name: 'ROWID', id: 'rowid', usageLevel: 2 },
 | 
			
		||||
    { name: 'UROWID', id: 'urowid', usageLevel: 2 },
 | 
			
		||||
 
 | 
			
		||||
@@ -3,37 +3,15 @@ import type { DataTypeData } from './data-types';
 | 
			
		||||
export const postgresDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    // Level 1 - Most commonly used types
 | 
			
		||||
    { name: 'integer', id: 'integer', usageLevel: 1 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varchar',
 | 
			
		||||
        id: 'varchar',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'varchar', id: 'varchar', hasCharMaxLength: true, usageLevel: 1 },
 | 
			
		||||
    { name: 'text', id: 'text', usageLevel: 1 },
 | 
			
		||||
    { name: 'boolean', id: 'boolean', usageLevel: 1 },
 | 
			
		||||
    { name: 'timestamp', id: 'timestamp', usageLevel: 1 },
 | 
			
		||||
    { name: 'timestamptz', id: 'timestamptz', usageLevel: 1 },
 | 
			
		||||
    { name: 'date', id: 'date', usageLevel: 1 },
 | 
			
		||||
 | 
			
		||||
    // Level 2 - Second most common types
 | 
			
		||||
    { name: 'bigint', id: 'bigint', usageLevel: 2 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'decimal',
 | 
			
		||||
        id: 'decimal',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 131072,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 10,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 16383,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 2,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'decimal', id: 'decimal', usageLevel: 2 },
 | 
			
		||||
    { name: 'serial', id: 'serial', usageLevel: 2 },
 | 
			
		||||
    { name: 'json', id: 'json', usageLevel: 2 },
 | 
			
		||||
    { name: 'jsonb', id: 'jsonb', usageLevel: 2 },
 | 
			
		||||
@@ -43,36 +21,20 @@ export const postgresDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
        id: 'timestamp_with_time_zone',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'int', id: 'int', usageLevel: 2 },
 | 
			
		||||
 | 
			
		||||
    // Less common types
 | 
			
		||||
    {
 | 
			
		||||
        name: 'numeric',
 | 
			
		||||
        id: 'numeric',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 131072,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 10,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 16383,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 2,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'numeric', id: 'numeric' },
 | 
			
		||||
    { name: 'real', id: 'real' },
 | 
			
		||||
    { name: 'double precision', id: 'double_precision' },
 | 
			
		||||
    { name: 'smallserial', id: 'smallserial' },
 | 
			
		||||
    { name: 'bigserial', id: 'bigserial' },
 | 
			
		||||
    { name: 'money', id: 'money' },
 | 
			
		||||
    { name: 'smallint', id: 'smallint' },
 | 
			
		||||
    { name: 'char', id: 'char', fieldAttributes: { hasCharMaxLength: true } },
 | 
			
		||||
    { name: 'char', id: 'char', hasCharMaxLength: true },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'character varying',
 | 
			
		||||
        id: 'character_varying',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
        hasCharMaxLength: true,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'time', id: 'time' },
 | 
			
		||||
    { name: 'timestamp without time zone', id: 'timestamp_without_time_zone' },
 | 
			
		||||
@@ -97,6 +59,7 @@ export const postgresDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    { name: 'tsvector', id: 'tsvector' },
 | 
			
		||||
    { name: 'tsquery', id: 'tsquery' },
 | 
			
		||||
    { name: 'xml', id: 'xml' },
 | 
			
		||||
    { name: 'array', id: 'array' },
 | 
			
		||||
    { name: 'int4range', id: 'int4range' },
 | 
			
		||||
    { name: 'int8range', id: 'int8range' },
 | 
			
		||||
    { name: 'numrange', id: 'numrange' },
 | 
			
		||||
 
 | 
			
		||||
@@ -4,93 +4,32 @@ export const sqlServerDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
    // Level 1 - Most commonly used types
 | 
			
		||||
    { name: 'int', id: 'int', usageLevel: 1 },
 | 
			
		||||
    { name: 'bit', id: 'bit', usageLevel: 1 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varchar',
 | 
			
		||||
        id: 'varchar',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            hasCharMaxLength: true,
 | 
			
		||||
            hasCharMaxLengthOption: true,
 | 
			
		||||
            maxLength: 8000,
 | 
			
		||||
        },
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'nvarchar',
 | 
			
		||||
        id: 'nvarchar',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            hasCharMaxLength: true,
 | 
			
		||||
            hasCharMaxLengthOption: true,
 | 
			
		||||
            maxLength: 4000,
 | 
			
		||||
        },
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'varchar', id: 'varchar', hasCharMaxLength: true, usageLevel: 1 },
 | 
			
		||||
    { name: 'nvarchar', id: 'nvarchar', hasCharMaxLength: true, usageLevel: 1 },
 | 
			
		||||
    { name: 'text', id: 'text', usageLevel: 1 },
 | 
			
		||||
    { name: 'datetime', id: 'datetime', usageLevel: 1 },
 | 
			
		||||
    { name: 'date', id: 'date', usageLevel: 1 },
 | 
			
		||||
 | 
			
		||||
    // Level 2 - Second most common types
 | 
			
		||||
    { name: 'bigint', id: 'bigint', usageLevel: 2 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'decimal',
 | 
			
		||||
        id: 'decimal',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 38,
 | 
			
		||||
                min: 1,
 | 
			
		||||
                default: 18,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 38,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 0,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'decimal', id: 'decimal', usageLevel: 2 },
 | 
			
		||||
    { name: 'datetime2', id: 'datetime2', usageLevel: 2 },
 | 
			
		||||
    { name: 'uniqueidentifier', id: 'uniqueidentifier', usageLevel: 2 },
 | 
			
		||||
    { name: 'json', id: 'json', usageLevel: 2 },
 | 
			
		||||
 | 
			
		||||
    // Less common types
 | 
			
		||||
    {
 | 
			
		||||
        name: 'numeric',
 | 
			
		||||
        id: 'numeric',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            precision: {
 | 
			
		||||
                max: 38,
 | 
			
		||||
                min: 1,
 | 
			
		||||
                default: 18,
 | 
			
		||||
            },
 | 
			
		||||
            scale: {
 | 
			
		||||
                max: 38,
 | 
			
		||||
                min: 0,
 | 
			
		||||
                default: 0,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'numeric', id: 'numeric' },
 | 
			
		||||
    { name: 'smallint', id: 'smallint' },
 | 
			
		||||
    { name: 'smallmoney', id: 'smallmoney' },
 | 
			
		||||
    { name: 'tinyint', id: 'tinyint' },
 | 
			
		||||
    { name: 'money', id: 'money' },
 | 
			
		||||
    { name: 'float', id: 'float' },
 | 
			
		||||
    { name: 'real', id: 'real' },
 | 
			
		||||
    { name: 'char', id: 'char', fieldAttributes: { hasCharMaxLength: true } },
 | 
			
		||||
    { name: 'nchar', id: 'nchar', fieldAttributes: { hasCharMaxLength: true } },
 | 
			
		||||
    { name: 'char', id: 'char', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'nchar', id: 'nchar', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'ntext', id: 'ntext' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'binary',
 | 
			
		||||
        id: 'binary',
 | 
			
		||||
        fieldAttributes: { hasCharMaxLength: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varbinary',
 | 
			
		||||
        id: 'varbinary',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            hasCharMaxLength: true,
 | 
			
		||||
            hasCharMaxLengthOption: true,
 | 
			
		||||
            maxLength: 8000,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'binary', id: 'binary', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'varbinary', id: 'varbinary', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'image', id: 'image' },
 | 
			
		||||
    { name: 'datetimeoffset', id: 'datetimeoffset' },
 | 
			
		||||
    { name: 'smalldatetime', id: 'smalldatetime' },
 | 
			
		||||
 
 | 
			
		||||
@@ -10,48 +10,25 @@ export const sqliteDataTypes: readonly DataTypeData[] = [
 | 
			
		||||
 | 
			
		||||
    // SQLite type aliases and common types
 | 
			
		||||
    { name: 'int', id: 'int', usageLevel: 1 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'varchar',
 | 
			
		||||
        id: 'varchar',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            hasCharMaxLength: true,
 | 
			
		||||
        },
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'timestamp',
 | 
			
		||||
        id: 'timestamp',
 | 
			
		||||
        usageLevel: 1,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'varchar', id: 'varchar', hasCharMaxLength: true, usageLevel: 1 },
 | 
			
		||||
    { name: 'timestamp', id: 'timestamp', usageLevel: 1 },
 | 
			
		||||
    { name: 'date', id: 'date', usageLevel: 1 },
 | 
			
		||||
    { name: 'datetime', id: 'datetime', usageLevel: 1 },
 | 
			
		||||
    { name: 'boolean', id: 'boolean', usageLevel: 1 },
 | 
			
		||||
 | 
			
		||||
    // Level 2 - Second most common types
 | 
			
		||||
    { name: 'numeric', id: 'numeric', usageLevel: 2 },
 | 
			
		||||
    { name: 'decimal', id: 'decimal', usageLevel: 2 },
 | 
			
		||||
    { name: 'float', id: 'float', usageLevel: 2 },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'decimal',
 | 
			
		||||
        id: 'decimal',
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'double', id: 'double', usageLevel: 2 },
 | 
			
		||||
    { name: 'json', id: 'json', usageLevel: 2 },
 | 
			
		||||
 | 
			
		||||
    // Less common types (all map to SQLite storage classes)
 | 
			
		||||
    {
 | 
			
		||||
        name: 'char',
 | 
			
		||||
        id: 'char',
 | 
			
		||||
        fieldAttributes: {
 | 
			
		||||
            hasCharMaxLength: true,
 | 
			
		||||
        },
 | 
			
		||||
        usageLevel: 2,
 | 
			
		||||
    },
 | 
			
		||||
    { name: 'char', id: 'char', hasCharMaxLength: true },
 | 
			
		||||
    { name: 'binary', id: 'binary' },
 | 
			
		||||
    { name: 'varbinary', id: 'varbinary' },
 | 
			
		||||
    { name: 'smallint', id: 'smallint' },
 | 
			
		||||
    { name: 'bigint', id: 'bigint' },
 | 
			
		||||
    { name: 'bool', id: 'bool' },
 | 
			
		||||
    { name: 'boolean', id: 'boolean' }, // Added for smartquery compatibility
 | 
			
		||||
    { name: 'time', id: 'time' },
 | 
			
		||||
    { name: 'date', id: 'date' }, // Added for smartquery compatibility
 | 
			
		||||
    { name: 'datetime', id: 'datetime' }, // Added for smartquery compatibility
 | 
			
		||||
] as const;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,5 +4,4 @@ export const defaultSchemas: { [key in DatabaseType]?: string } = {
 | 
			
		||||
    [DatabaseType.POSTGRESQL]: 'public',
 | 
			
		||||
    [DatabaseType.SQL_SERVER]: 'dbo',
 | 
			
		||||
    [DatabaseType.CLICKHOUSE]: 'default',
 | 
			
		||||
    [DatabaseType.COCKROACHDB]: 'public',
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,20 @@
 | 
			
		||||
import { describe, it, expect } from 'vitest';
 | 
			
		||||
import { describe, it, expect, vi } from 'vitest';
 | 
			
		||||
import { exportBaseSQL } from '../export-sql-script';
 | 
			
		||||
import { DatabaseType } from '@/lib/domain/database-type';
 | 
			
		||||
import type { Diagram } from '@/lib/domain/diagram';
 | 
			
		||||
import type { DBTable } from '@/lib/domain/db-table';
 | 
			
		||||
import type { DBField } from '@/lib/domain/db-field';
 | 
			
		||||
 | 
			
		||||
// Mock the dbml/core importer
 | 
			
		||||
vi.mock('@dbml/core', () => ({
 | 
			
		||||
    importer: {
 | 
			
		||||
        import: vi.fn((sql: string) => {
 | 
			
		||||
            // Return a simplified DBML for testing
 | 
			
		||||
            return sql;
 | 
			
		||||
        }),
 | 
			
		||||
    },
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
    // Helper to generate test IDs and timestamps
 | 
			
		||||
    let idCounter = 0;
 | 
			
		||||
@@ -106,7 +116,7 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should contain composite primary key syntax
 | 
			
		||||
            expect(sql).toContain('PRIMARY KEY ("spell_id", "component_id")');
 | 
			
		||||
            expect(sql).toContain('PRIMARY KEY (spell_id, component_id)');
 | 
			
		||||
            // Should NOT contain individual PRIMARY KEY constraints
 | 
			
		||||
            expect(sql).not.toMatch(/spell_id\s+uuid\s+NOT NULL\s+PRIMARY KEY/);
 | 
			
		||||
            expect(sql).not.toMatch(
 | 
			
		||||
@@ -114,96 +124,6 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should not create duplicate index for composite primary key', () => {
 | 
			
		||||
            const tableId = testId();
 | 
			
		||||
            const field1Id = testId();
 | 
			
		||||
            const field2Id = testId();
 | 
			
		||||
            const field3Id = testId();
 | 
			
		||||
 | 
			
		||||
            const diagram: Diagram = createDiagram({
 | 
			
		||||
                id: testId(),
 | 
			
		||||
                name: 'Landlord System',
 | 
			
		||||
                databaseType: DatabaseType.POSTGRESQL,
 | 
			
		||||
                tables: [
 | 
			
		||||
                    createTable({
 | 
			
		||||
                        id: tableId,
 | 
			
		||||
                        name: 'users_master_table',
 | 
			
		||||
                        schema: 'landlord',
 | 
			
		||||
                        fields: [
 | 
			
		||||
                            createField({
 | 
			
		||||
                                id: field1Id,
 | 
			
		||||
                                name: 'master_user_id',
 | 
			
		||||
                                type: { id: 'bigint', name: 'bigint' },
 | 
			
		||||
                                primaryKey: true,
 | 
			
		||||
                                nullable: false,
 | 
			
		||||
                                unique: false,
 | 
			
		||||
                            }),
 | 
			
		||||
                            createField({
 | 
			
		||||
                                id: field2Id,
 | 
			
		||||
                                name: 'tenant_id',
 | 
			
		||||
                                type: { id: 'bigint', name: 'bigint' },
 | 
			
		||||
                                primaryKey: true,
 | 
			
		||||
                                nullable: false,
 | 
			
		||||
                                unique: false,
 | 
			
		||||
                            }),
 | 
			
		||||
                            createField({
 | 
			
		||||
                                id: field3Id,
 | 
			
		||||
                                name: 'tenant_user_id',
 | 
			
		||||
                                type: { id: 'bigint', name: 'bigint' },
 | 
			
		||||
                                primaryKey: true,
 | 
			
		||||
                                nullable: false,
 | 
			
		||||
                                unique: false,
 | 
			
		||||
                            }),
 | 
			
		||||
                            createField({
 | 
			
		||||
                                id: testId(),
 | 
			
		||||
                                name: 'enabled',
 | 
			
		||||
                                type: { id: 'boolean', name: 'boolean' },
 | 
			
		||||
                                primaryKey: false,
 | 
			
		||||
                                nullable: true,
 | 
			
		||||
                                unique: false,
 | 
			
		||||
                            }),
 | 
			
		||||
                        ],
 | 
			
		||||
                        indexes: [
 | 
			
		||||
                            {
 | 
			
		||||
                                id: testId(),
 | 
			
		||||
                                name: 'idx_users_master_table_master_user_id_tenant_id_tenant_user_id',
 | 
			
		||||
                                unique: false,
 | 
			
		||||
                                fieldIds: [field1Id, field2Id, field3Id],
 | 
			
		||||
                                createdAt: testTime,
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                id: testId(),
 | 
			
		||||
                                name: 'index_1',
 | 
			
		||||
                                unique: true,
 | 
			
		||||
                                fieldIds: [field2Id, field3Id],
 | 
			
		||||
                                createdAt: testTime,
 | 
			
		||||
                            },
 | 
			
		||||
                        ],
 | 
			
		||||
                    }),
 | 
			
		||||
                ],
 | 
			
		||||
                relationships: [],
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const sql = exportBaseSQL({
 | 
			
		||||
                diagram,
 | 
			
		||||
                targetDatabaseType: DatabaseType.POSTGRESQL,
 | 
			
		||||
                isDBMLFlow: true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should contain composite primary key constraint
 | 
			
		||||
            expect(sql).toContain(
 | 
			
		||||
                'PRIMARY KEY ("master_user_id", "tenant_id", "tenant_user_id")'
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Should NOT contain the duplicate index for the primary key fields
 | 
			
		||||
            expect(sql).not.toContain(
 | 
			
		||||
                'CREATE INDEX idx_users_master_table_master_user_id_tenant_id_tenant_user_id'
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Should still contain the unique index on subset of fields
 | 
			
		||||
            expect(sql).toContain('CREATE UNIQUE INDEX index_1');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should handle single primary keys inline', () => {
 | 
			
		||||
            const diagram: Diagram = createDiagram({
 | 
			
		||||
                id: testId(),
 | 
			
		||||
@@ -245,7 +165,7 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should contain inline PRIMARY KEY
 | 
			
		||||
            expect(sql).toMatch(/"id"\s+uuid\s+NOT NULL\s+PRIMARY KEY/);
 | 
			
		||||
            expect(sql).toMatch(/id\s+uuid\s+NOT NULL\s+PRIMARY KEY/);
 | 
			
		||||
            // Should NOT contain separate PRIMARY KEY constraint
 | 
			
		||||
            expect(sql).not.toContain('PRIMARY KEY (id)');
 | 
			
		||||
        });
 | 
			
		||||
@@ -306,8 +226,8 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            expect(sql).not.toContain('DEFAULT has default');
 | 
			
		||||
            expect(sql).not.toContain('DEFAULT DEFAULT has default');
 | 
			
		||||
            // The fields should still be in the table
 | 
			
		||||
            expect(sql).toContain('"is_active" boolean');
 | 
			
		||||
            expect(sql).toContain('"stock_count" integer NOT NULL'); // integer gets simplified to int
 | 
			
		||||
            expect(sql).toContain('is_active boolean');
 | 
			
		||||
            expect(sql).toContain('stock_count int NOT NULL'); // integer gets simplified to int
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should handle valid default values correctly', () => {
 | 
			
		||||
@@ -429,8 +349,8 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should convert NOW to NOW() and ('now') to now()
 | 
			
		||||
            expect(sql).toContain('"created_at" timestamp DEFAULT NOW');
 | 
			
		||||
            expect(sql).toContain('"updated_at" timestamp DEFAULT now()');
 | 
			
		||||
            expect(sql).toContain('created_at timestamp DEFAULT NOW');
 | 
			
		||||
            expect(sql).toContain('updated_at timestamp DEFAULT now()');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@@ -485,9 +405,9 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should handle char with explicit length
 | 
			
		||||
            expect(sql).toContain('"element_code" char(2)');
 | 
			
		||||
            expect(sql).toContain('element_code char(2)');
 | 
			
		||||
            // Should add default length for char without length
 | 
			
		||||
            expect(sql).toContain('"status" char(1)');
 | 
			
		||||
            expect(sql).toContain('status char(1)');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should not have spaces between char and parentheses', () => {
 | 
			
		||||
@@ -596,7 +516,7 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should create a valid table without primary key
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE "experiment_logs"');
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE experiment_logs');
 | 
			
		||||
            expect(sql).not.toContain('PRIMARY KEY');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -711,11 +631,11 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should create both tables
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE "guilds"');
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE "guild_members"');
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE guilds');
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE guild_members');
 | 
			
		||||
            // Should create foreign key
 | 
			
		||||
            expect(sql).toContain(
 | 
			
		||||
                'ALTER TABLE "guild_members" ADD CONSTRAINT fk_guild_members_guild FOREIGN KEY ("guild_id") REFERENCES "guilds" ("id");'
 | 
			
		||||
                'ALTER TABLE guild_members ADD CONSTRAINT fk_guild_members_guild FOREIGN KEY (guild_id) REFERENCES guilds (id)'
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
@@ -789,9 +709,12 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
                isDBMLFlow: true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should create schemas
 | 
			
		||||
            expect(sql).toContain('CREATE SCHEMA IF NOT EXISTS transportation');
 | 
			
		||||
            expect(sql).toContain('CREATE SCHEMA IF NOT EXISTS magic');
 | 
			
		||||
            // Should use schema-qualified table names
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE "transportation"."portals"');
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE "magic"."spells"');
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE transportation.portals');
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE magic.spells');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@@ -838,7 +761,7 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should still create table structure
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE "empty_table"');
 | 
			
		||||
            expect(sql).toContain('CREATE TABLE empty_table');
 | 
			
		||||
            expect(sql).toContain('(\n\n)');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -939,9 +862,9 @@ describe('DBML Export - SQL Generation Tests', () => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Should include precision and scale
 | 
			
		||||
            expect(sql).toContain('"amount" numeric(15, 2)');
 | 
			
		||||
            expect(sql).toContain('amount numeric(15, 2)');
 | 
			
		||||
            // Should include precision only when scale is not provided
 | 
			
		||||
            expect(sql).toContain('"interest_rate" numeric(5)');
 | 
			
		||||
            expect(sql).toContain('interest_rate numeric(5)');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user