From 3cabb1a4771a8f2cd095827ef22e737878f0be33 Mon Sep 17 00:00:00 2001 From: markankamaransheogarat-sys <279850453+markankamaransheogarat-sys@users.noreply.github.com> Date: Sat, 7 Nov 2026 09:12:16 +0000 Subject: [PATCH 1/2] feat(er-diagram): add accessible key and relationship legend (#1401) --- .../src/components/ui/SchemaDiagram.tsx | 3 + .../src/components/ui/SchemaDiagramLegend.tsx | 119 ++++++++++++++++++ packages/web-ui/src/i18n/locales/de.json | 9 +- packages/web-ui/src/i18n/locales/en.json | 9 +- packages/web-ui/src/i18n/locales/es.json | 9 +- packages/web-ui/src/i18n/locales/fr.json | 9 +- packages/web-ui/src/i18n/locales/it.json | 9 +- packages/web-ui/src/i18n/locales/ja.json | 9 +- packages/web-ui/src/i18n/locales/ko.json | 9 +- packages/web-ui/src/i18n/locales/pt-BR.json | 9 +- packages/web-ui/src/i18n/locales/ru.json | 9 +- packages/web-ui/src/i18n/locales/tl.json | 9 +- packages/web-ui/src/i18n/locales/vi.json | 9 +- packages/web-ui/src/i18n/locales/zh-TW.json | 9 +- packages/web-ui/src/i18n/locales/zh.json | 9 +- .../ui/SchemaDiagramLegend.test.tsx | 58 +++++++++ 16 files changed, 284 insertions(+), 13 deletions(-) create mode 100644 packages/web-ui/src/components/ui/SchemaDiagramLegend.tsx create mode 100644 packages/web-ui/tests/components/ui/SchemaDiagramLegend.test.tsx diff --git a/packages/web-ui/src/components/ui/SchemaDiagram.tsx b/packages/web-ui/src/components/ui/SchemaDiagram.tsx index bc69d7187..5cbf850ca 100644 --- a/packages/web-ui/src/components/ui/SchemaDiagram.tsx +++ b/packages/web-ui/src/components/ui/SchemaDiagram.tsx @@ -17,6 +17,7 @@ import '@xyflow/react/dist/style.css'; import dagre from 'dagre'; import {useEditor} from '@/hooks/useEditor'; import {SchemaTableNodeComponent} from './SchemaTableNode'; +import {SchemaDiagramLegend} from './SchemaDiagramLegend'; import { Loader2, ArrowLeftRight, @@ -428,6 +429,8 @@ const SchemaDiagramContent = ({ {/* Toolbar per i controlli */}
+ + + + {isOpen && ( +
+ {/* Primary Key Item */} +
+
+ +
+
+ + {t('erDiagram.primaryKey', 'Primary Key')} + + + {t( + 'erDiagram.primaryKeyDesc', + 'Unique column identifying rows in the table', + )} + +
+
+ + {/* Foreign Key Item */} +
+
+ +
+
+ + {t('erDiagram.foreignKey', 'Foreign Key')} + + + {t( + 'erDiagram.foreignKeyDesc', + 'References a primary or unique key in another table', + )} + +
+
+ + {/* Relationship Connector */} +
+
+
+
+
+ + {t('erDiagram.relationship', 'Relationship')} + + + {t( + 'erDiagram.relationshipDesc', + 'Foreign key reference connecting child and parent tables', + )} + +
+
+
+ )} +
+ ); +}); diff --git a/packages/web-ui/src/i18n/locales/de.json b/packages/web-ui/src/i18n/locales/de.json index 4036a64a9..e99319b18 100644 --- a/packages/web-ui/src/i18n/locales/de.json +++ b/packages/web-ui/src/i18n/locales/de.json @@ -2188,7 +2188,14 @@ "exportMermaid": "Als Mermaid-Diagramm exportieren", "exportSuccess": "Diagramm exportiert", "exportDbml": "Als DBML exportieren", - "export": "Exportieren" + "export": "Exportieren", + "legend": "Legende", + "primaryKey": "Primärschlüssel", + "primaryKeyDesc": "Eindeutige Spalte zur Zeilenidentifikation in der Tabelle", + "foreignKey": "Fremdschlüssel", + "foreignKeyDesc": "Verweist auf einen Primär- oder eindeutigen Schlüssel einer anderen Tabelle", + "relationship": "Beziehung", + "relationshipDesc": "Fremdschlüssel-Referenz zwischen untergeordneter und übergeordneter Tabelle" }, "views": { "createView": "Ansicht erstellen", diff --git a/packages/web-ui/src/i18n/locales/en.json b/packages/web-ui/src/i18n/locales/en.json index 177d39a89..1b49fa9eb 100644 --- a/packages/web-ui/src/i18n/locales/en.json +++ b/packages/web-ui/src/i18n/locales/en.json @@ -2259,7 +2259,14 @@ "exportMermaid": "Export as Mermaid diagram", "exportSuccess": "Diagram exported", "exportDbml": "Export as DBML", - "export": "Export" + "export": "Export", + "legend": "Legend", + "primaryKey": "Primary Key", + "primaryKeyDesc": "Unique column identifying rows in the table", + "foreignKey": "Foreign Key", + "foreignKeyDesc": "References a primary or unique key in another table", + "relationship": "Relationship", + "relationshipDesc": "Foreign key reference connecting child and parent tables" }, "views": { "createView": "Create View", diff --git a/packages/web-ui/src/i18n/locales/es.json b/packages/web-ui/src/i18n/locales/es.json index 3354f4eed..29426b0c1 100644 --- a/packages/web-ui/src/i18n/locales/es.json +++ b/packages/web-ui/src/i18n/locales/es.json @@ -2159,7 +2159,14 @@ "exportMermaid": "Exportar como diagrama Mermaid", "exportSuccess": "Diagrama exportado", "exportDbml": "Exportar como DBML", - "export": "Exportar" + "export": "Exportar", + "legend": "Leyenda", + "primaryKey": "Clave primaria", + "primaryKeyDesc": "Columna única que identifica filas en la tabla", + "foreignKey": "Clave foránea", + "foreignKeyDesc": "Hace referencia a una clave primaria o única en otra tabla", + "relationship": "Relación", + "relationshipDesc": "Referencia de clave foránea entre tablas secundarias y principales" }, "views": { "createView": "Crear Vista", diff --git a/packages/web-ui/src/i18n/locales/fr.json b/packages/web-ui/src/i18n/locales/fr.json index 7e00adb8c..02ec37a0a 100644 --- a/packages/web-ui/src/i18n/locales/fr.json +++ b/packages/web-ui/src/i18n/locales/fr.json @@ -2228,7 +2228,14 @@ "exportMermaid": "Exporter en diagramme Mermaid", "exportSuccess": "Diagramme exporté", "exportDbml": "Exporter en DBML", - "export": "Exporter" + "export": "Exporter", + "legend": "Légende", + "primaryKey": "Clé primaire", + "primaryKeyDesc": "Colonne unique identifiant les lignes de la table", + "foreignKey": "Clé étrangère", + "foreignKeyDesc": "Fait référence à une clé primaire ou unique dans une autre table", + "relationship": "Relation", + "relationshipDesc": "Référence de clé étrangère reliant les tables enfants et parentes" }, "views": { "createView": "Créer une vue", diff --git a/packages/web-ui/src/i18n/locales/it.json b/packages/web-ui/src/i18n/locales/it.json index 9783f56e8..bdbda3a76 100644 --- a/packages/web-ui/src/i18n/locales/it.json +++ b/packages/web-ui/src/i18n/locales/it.json @@ -2248,7 +2248,14 @@ "exportMermaid": "Esporta come diagramma Mermaid", "exportSuccess": "Diagramma esportato", "exportDbml": "Esporta come DBML", - "export": "Esporta" + "export": "Esporta", + "legend": "Legenda", + "primaryKey": "Chiave primaria", + "primaryKeyDesc": "Colonna univoca che identifica le righe della tabella", + "foreignKey": "Chiave esterna", + "foreignKeyDesc": "Fa riferimento a una chiave primaria o univoca in un'altra tabella", + "relationship": "Relazione", + "relationshipDesc": "Riferimento di chiave esterna tra tabella figlia e genitore" }, "views": { "createView": "Crea Vista", diff --git a/packages/web-ui/src/i18n/locales/ja.json b/packages/web-ui/src/i18n/locales/ja.json index 6025712e9..f71617976 100644 --- a/packages/web-ui/src/i18n/locales/ja.json +++ b/packages/web-ui/src/i18n/locales/ja.json @@ -2199,7 +2199,14 @@ "exportMermaid": "Mermaid 図としてエクスポート", "exportSuccess": "図をエクスポートしました", "exportDbml": "DBML としてエクスポート", - "export": "エクスポート" + "export": "エクスポート", + "legend": "凡例", + "primaryKey": "主キー", + "primaryKeyDesc": "テーブル内の行を一意に識別する列", + "foreignKey": "外部キー", + "foreignKeyDesc": "別のテーブルの主キーまたは一意キーを参照します", + "relationship": "リレーション", + "relationshipDesc": "子テーブルと親テーブルを結ぶ外部キー参照" }, "views": { "createView": "ビューを作成", diff --git a/packages/web-ui/src/i18n/locales/ko.json b/packages/web-ui/src/i18n/locales/ko.json index 437d8a546..5319b6a9d 100644 --- a/packages/web-ui/src/i18n/locales/ko.json +++ b/packages/web-ui/src/i18n/locales/ko.json @@ -2162,7 +2162,14 @@ "exportMermaid": "Mermaid 다이어그램으로 내보내기", "exportSuccess": "다이어그램 내보내기 완료", "exportDbml": "DBML로 내보내기", - "export": "내보내기" + "export": "내보내기", + "legend": "범례", + "primaryKey": "기본 키", + "primaryKeyDesc": "테이블의 행을 고유하게 식별하는 열", + "foreignKey": "외래 키", + "foreignKeyDesc": "다른 테이블의 기본 키 또는 고유 키를 참조합니다", + "relationship": "관계", + "relationshipDesc": "하위 테이블과 상위 테이블을 연결하는 외래 키 참조" }, "views": { "createView": "뷰 생성", diff --git a/packages/web-ui/src/i18n/locales/pt-BR.json b/packages/web-ui/src/i18n/locales/pt-BR.json index 833fce0e3..53036a354 100644 --- a/packages/web-ui/src/i18n/locales/pt-BR.json +++ b/packages/web-ui/src/i18n/locales/pt-BR.json @@ -2202,7 +2202,14 @@ "showAllTables": "Mostrar Todas as Tabelas", "showAll": "Mostrar Tudo", "focusedOn": "Focado em", - "focusOnTable": "Focar na Tabela" + "focusOnTable": "Focar na Tabela", + "legend": "Legenda", + "primaryKey": "Chave primária", + "primaryKeyDesc": "Coluna exclusiva que identifica linhas na tabela", + "foreignKey": "Chave estrangeira", + "foreignKeyDesc": "Faz referência a uma chave primária ou exclusiva em outra tabela", + "relationship": "Relacionamento", + "relationshipDesc": "Referência de chave estrangeira entre tabelas dependentes e principais" }, "views": { "createView": "Criar View", diff --git a/packages/web-ui/src/i18n/locales/ru.json b/packages/web-ui/src/i18n/locales/ru.json index 4e14ebb47..e016f1ecd 100644 --- a/packages/web-ui/src/i18n/locales/ru.json +++ b/packages/web-ui/src/i18n/locales/ru.json @@ -2209,7 +2209,14 @@ "exportMermaid": "Экспортировать как диаграмму Mermaid", "exportSuccess": "Диаграмма экспортирована", "exportDbml": "Экспортировать как DBML", - "export": "Экспорт" + "export": "Экспорт", + "legend": "Легенда", + "primaryKey": "Первичный ключ", + "primaryKeyDesc": "Уникальный столбец, идентифицирующий строки в таблице", + "foreignKey": "Внешний ключ", + "foreignKeyDesc": "Ссылается на первичный или уникальный ключ в другой таблице", + "relationship": "Связь", + "relationshipDesc": "Связь по внешнему ключу между дочерней и родительской таблицами" }, "views": { "createView": "Создать представление", diff --git a/packages/web-ui/src/i18n/locales/tl.json b/packages/web-ui/src/i18n/locales/tl.json index 11b8ad5b4..78538fd16 100644 --- a/packages/web-ui/src/i18n/locales/tl.json +++ b/packages/web-ui/src/i18n/locales/tl.json @@ -2218,7 +2218,14 @@ "exportMermaid": "I-export bilang Mermaid diagram", "exportSuccess": "Na-export ang diagram", "exportDbml": "I-export bilang DBML", - "export": "I-export" + "export": "I-export", + "legend": "Alamat", + "primaryKey": "Primary Key", + "primaryKeyDesc": "Natatanging column na tumutukoy sa mga hilera sa talahanayan", + "foreignKey": "Foreign Key", + "foreignKeyDesc": "Sumasangguni sa primary o natatanging key sa ibang talahanayan", + "relationship": "Ugnayan", + "relationshipDesc": "Sanggunian ng foreign key na nag-uugnay sa mga kaugnay na talahanayan" }, "views": { "createView": "Gumawa ng View", diff --git a/packages/web-ui/src/i18n/locales/vi.json b/packages/web-ui/src/i18n/locales/vi.json index 42930f89f..848b0c3fe 100644 --- a/packages/web-ui/src/i18n/locales/vi.json +++ b/packages/web-ui/src/i18n/locales/vi.json @@ -2242,7 +2242,14 @@ "exportMermaid": "Xuất ra sơ đồ Mermaid", "exportSuccess": "Đã xuất sơ đồ", "exportDbml": "Xuất ra DBML", - "export": "Xuất" + "export": "Xuất", + "legend": "Chú giải", + "primaryKey": "Khóa chính", + "primaryKeyDesc": "Cột duy nhất xác định các hàng trong bảng", + "foreignKey": "Khóa ngoại", + "foreignKeyDesc": "Tham chiếu khóa chính hoặc khóa duy nhất trong bảng khác", + "relationship": "Quan hệ", + "relationshipDesc": "Tham chiếu khóa ngoại kết nối bảng con và bảng cha" }, "views": { "createView": "Tạo view", diff --git a/packages/web-ui/src/i18n/locales/zh-TW.json b/packages/web-ui/src/i18n/locales/zh-TW.json index 17b452eb7..a956ee78c 100644 --- a/packages/web-ui/src/i18n/locales/zh-TW.json +++ b/packages/web-ui/src/i18n/locales/zh-TW.json @@ -2241,7 +2241,14 @@ "exportMermaid": "匯出為 Mermaid 圖表", "exportSuccess": "圖表已匯出", "exportDbml": "匯出為 DBML", - "export": "匯出" + "export": "匯出", + "legend": "圖例", + "primaryKey": "主鍵", + "primaryKeyDesc": "唯一識別表中列的欄位", + "foreignKey": "外鍵", + "foreignKeyDesc": "引用另一個表中的主鍵或唯一鍵", + "relationship": "關聯", + "relationshipDesc": "連接子表與父表的外键引用" }, "views": { "createView": "建立檢視", diff --git a/packages/web-ui/src/i18n/locales/zh.json b/packages/web-ui/src/i18n/locales/zh.json index 04d3ffa4e..4b582bb05 100644 --- a/packages/web-ui/src/i18n/locales/zh.json +++ b/packages/web-ui/src/i18n/locales/zh.json @@ -2141,7 +2141,14 @@ "exportMermaid": "导出为 Mermaid 图表", "exportSuccess": "图表已导出", "exportDbml": "导出为 DBML", - "export": "导出" + "export": "导出", + "legend": "图例", + "primaryKey": "主键", + "primaryKeyDesc": "唯一标识表中行的列", + "foreignKey": "外键", + "foreignKeyDesc": "引用另一个表中的主键或唯一键", + "relationship": "关系", + "relationshipDesc": "连接子表与父表的外键引用" }, "views": { "createView": "创建视图", diff --git a/packages/web-ui/tests/components/ui/SchemaDiagramLegend.test.tsx b/packages/web-ui/tests/components/ui/SchemaDiagramLegend.test.tsx new file mode 100644 index 000000000..6c31242aa --- /dev/null +++ b/packages/web-ui/tests/components/ui/SchemaDiagramLegend.test.tsx @@ -0,0 +1,58 @@ +import {render, screen, fireEvent} from '@testing-library/react'; +import {describe, expect, it, vi} from 'vitest'; +import {SchemaDiagramLegend} from '@/components/ui/SchemaDiagramLegend'; + +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string, fallback?: string) => fallback ?? key, + }), +})); + +describe('SchemaDiagramLegend', () => { + it('renders collapsed by default with accessible attributes', () => { + render(); + + const trigger = screen.getByRole('button', {name: /legend/i}); + expect(trigger).toBeInTheDocument(); + expect(trigger).toHaveAttribute('aria-expanded', 'false'); + expect(screen.queryByText('Primary Key')).not.toBeInTheDocument(); + expect(screen.queryByText('Foreign Key')).not.toBeInTheDocument(); + expect(screen.queryByText('Relationship')).not.toBeInTheDocument(); + }); + + it('expands when clicked and displays accurate PK, FK and relationship items', () => { + render(); + + const trigger = screen.getByRole('button', {name: /legend/i}); + fireEvent.click(trigger); + + expect(trigger).toHaveAttribute('aria-expanded', 'true'); + expect(screen.getByText('Primary Key')).toBeInTheDocument(); + expect(screen.getByText('Unique column identifying rows in the table')).toBeInTheDocument(); + expect(screen.getByText('Foreign Key')).toBeInTheDocument(); + expect( + screen.getByText('References a primary or unique key in another table'), + ).toBeInTheDocument(); + expect(screen.getByText('Relationship')).toBeInTheDocument(); + expect( + screen.getByText('Foreign key reference connecting child and parent tables'), + ).toBeInTheDocument(); + + // Clicking again collapses the legend + fireEvent.click(trigger); + expect(trigger).toHaveAttribute('aria-expanded', 'false'); + expect(screen.queryByText('Primary Key')).not.toBeInTheDocument(); + }); + + it('collapses on Escape key when open', () => { + render(); + + const trigger = screen.getByRole('button', {name: /legend/i}); + fireEvent.click(trigger); + expect(trigger).toHaveAttribute('aria-expanded', 'true'); + + fireEvent.keyDown(window, {key: 'Escape'}); + expect(trigger).toHaveAttribute('aria-expanded', 'false'); + expect(screen.queryByText('Primary Key')).not.toBeInTheDocument(); + }); +}); From be749d0f8a42e20e6c0670d154e01e70c62c921f Mon Sep 17 00:00:00 2001 From: markankamaransheogarat-sys <279850453+markankamaransheogarat-sys@users.noreply.github.com> Date: Sat, 7 Nov 2026 09:18:03 +0000 Subject: [PATCH 2/2] fix(er-diagram): address code review feedback on popover layout, useEscapeKey and locales --- .../src/components/ui/SchemaDiagram.tsx | 2 +- .../src/components/ui/SchemaDiagramLegend.tsx | 39 +++++++------------ packages/web-ui/src/i18n/locales/tl.json | 2 +- packages/web-ui/src/i18n/locales/zh-TW.json | 2 +- 4 files changed, 16 insertions(+), 29 deletions(-) diff --git a/packages/web-ui/src/components/ui/SchemaDiagram.tsx b/packages/web-ui/src/components/ui/SchemaDiagram.tsx index 5cbf850ca..d7833ab04 100644 --- a/packages/web-ui/src/components/ui/SchemaDiagram.tsx +++ b/packages/web-ui/src/components/ui/SchemaDiagram.tsx @@ -428,7 +428,7 @@ const SchemaDiagramContent = ({ )} {/* Toolbar per i controlli */} -
+