mirror of
https://github.com/chartdb/chartdb.git
synced 2026-04-30 06:39:48 -05:00
fix(canvas): add right-click option to create relationships (#568)
* feat(create-relationship): add right-click option to easy create relationships * add missing translations * fix --------- Co-authored-by: Guy Ben-Aharon <baguy3@gmail.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import type { ExportSQLDialogProps } from '@/dialogs/export-sql-dialog/export-sq
|
||||
import type { ExportImageDialogProps } from '@/dialogs/export-image-dialog/export-image-dialog';
|
||||
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';
|
||||
|
||||
export interface DialogContext {
|
||||
// Create diagram dialog
|
||||
@@ -21,7 +22,9 @@ export interface DialogContext {
|
||||
closeExportSQLDialog: () => void;
|
||||
|
||||
// Create relationship dialog
|
||||
openCreateRelationshipDialog: () => void;
|
||||
openCreateRelationshipDialog: (
|
||||
params?: Omit<CreateRelationshipDialogProps, 'dialog'>
|
||||
) => void;
|
||||
closeCreateRelationshipDialog: () => void;
|
||||
|
||||
// Import database dialog
|
||||
|
||||
@@ -6,6 +6,7 @@ import { OpenDiagramDialog } from '@/dialogs/open-diagram-dialog/open-diagram-di
|
||||
import type { ExportSQLDialogProps } from '@/dialogs/export-sql-dialog/export-sql-dialog';
|
||||
import { ExportSQLDialog } from '@/dialogs/export-sql-dialog/export-sql-dialog';
|
||||
import { DatabaseType } from '@/lib/domain/database-type';
|
||||
import type { CreateRelationshipDialogProps } from '@/dialogs/create-relationship-dialog/create-relationship-dialog';
|
||||
import { CreateRelationshipDialog } from '@/dialogs/create-relationship-dialog/create-relationship-dialog';
|
||||
import type { ImportDatabaseDialogProps } from '@/dialogs/import-database-dialog/import-database-dialog';
|
||||
import { ImportDatabaseDialog } from '@/dialogs/import-database-dialog/import-database-dialog';
|
||||
@@ -28,6 +29,17 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
|
||||
const [openCreateRelationshipDialog, setOpenCreateRelationshipDialog] =
|
||||
useState(false);
|
||||
const [createRelationshipDialogParams, setCreateRelationshipDialogParams] =
|
||||
useState<Omit<CreateRelationshipDialogProps, 'dialog'>>();
|
||||
const openCreateRelationshipDialogHandler: DialogContext['openCreateRelationshipDialog'] =
|
||||
useCallback(
|
||||
(params) => {
|
||||
setCreateRelationshipDialogParams(params);
|
||||
setOpenCreateRelationshipDialog(true);
|
||||
},
|
||||
[setOpenCreateRelationshipDialog]
|
||||
);
|
||||
|
||||
const [openStarUsDialog, setOpenStarUsDialog] = useState(false);
|
||||
const [openBuckleDialog, setOpenBuckleDialog] = useState(false);
|
||||
|
||||
@@ -109,8 +121,8 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
closeOpenDiagramDialog: () => setOpenOpenDiagramDialog(false),
|
||||
openExportSQLDialog: openExportSQLDialogHandler,
|
||||
closeExportSQLDialog: () => setOpenExportSQLDialog(false),
|
||||
openCreateRelationshipDialog: () =>
|
||||
setOpenCreateRelationshipDialog(true),
|
||||
openCreateRelationshipDialog:
|
||||
openCreateRelationshipDialogHandler,
|
||||
closeCreateRelationshipDialog: () =>
|
||||
setOpenCreateRelationshipDialog(false),
|
||||
openImportDatabaseDialog: openImportDatabaseDialogHandler,
|
||||
@@ -143,6 +155,7 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
/>
|
||||
<CreateRelationshipDialog
|
||||
dialog={{ open: openCreateRelationshipDialog }}
|
||||
{...createRelationshipDialogParams}
|
||||
/>
|
||||
<ImportDatabaseDialog
|
||||
dialog={{ open: openImportDatabaseDialog }}
|
||||
|
||||
@@ -22,13 +22,17 @@ import { areFieldTypesCompatible } from '@/lib/data/data-types/data-types';
|
||||
const ErrorMessageRelationshipFieldsNotSameType =
|
||||
'Relationships can only be created between fields of the same type';
|
||||
|
||||
export interface CreateRelationshipDialogProps extends BaseDialogProps {}
|
||||
export interface CreateRelationshipDialogProps extends BaseDialogProps {
|
||||
sourceTableId?: string;
|
||||
}
|
||||
|
||||
export const CreateRelationshipDialog: React.FC<
|
||||
CreateRelationshipDialogProps
|
||||
> = ({ dialog }) => {
|
||||
> = ({ dialog, sourceTableId: preSelectedSourceTableId }) => {
|
||||
const { closeCreateRelationshipDialog } = useDialog();
|
||||
const [primaryTableId, setPrimaryTableId] = useState<string | undefined>();
|
||||
const [primaryTableId, setPrimaryTableId] = useState<string | undefined>(
|
||||
preSelectedSourceTableId
|
||||
);
|
||||
const [primaryFieldId, setPrimaryFieldId] = useState<string | undefined>();
|
||||
const [referencedTableId, setReferencedTableId] = useState<
|
||||
string | undefined
|
||||
@@ -43,6 +47,9 @@ export const CreateRelationshipDialog: React.FC<
|
||||
const [canCreateRelationship, setCanCreateRelationship] = useState(false);
|
||||
const { fitView, setEdges } = useReactFlow();
|
||||
const { databaseType } = useChartDB();
|
||||
const [primaryFieldSelectOpen, setPrimaryFieldSelectOpen] = useState(false);
|
||||
const [referencedTableSelectOpen, setReferencedTableSelectOpen] =
|
||||
useState(false);
|
||||
|
||||
const tableOptions = useMemo(() => {
|
||||
return tables.map(
|
||||
@@ -89,8 +96,23 @@ export const CreateRelationshipDialog: React.FC<
|
||||
setReferencedTableId(undefined);
|
||||
setReferencedFieldId(undefined);
|
||||
setErrorMessage('');
|
||||
setPrimaryFieldSelectOpen(false);
|
||||
setReferencedTableSelectOpen(false);
|
||||
}, [dialog.open]);
|
||||
|
||||
useEffect(() => {
|
||||
if (preSelectedSourceTableId) {
|
||||
const table = getTable(preSelectedSourceTableId);
|
||||
if (table) {
|
||||
setPrimaryTableId(preSelectedSourceTableId);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
setPrimaryFieldSelectOpen(true);
|
||||
}, 100);
|
||||
}
|
||||
}, [preSelectedSourceTableId, getTable]);
|
||||
|
||||
useEffect(() => {
|
||||
setCanCreateRelationship(false);
|
||||
setErrorMessage('');
|
||||
@@ -223,8 +245,14 @@ export const CreateRelationshipDialog: React.FC<
|
||||
)}
|
||||
value={primaryTableId}
|
||||
onChange={(value) => {
|
||||
setPrimaryTableId(value as string);
|
||||
setPrimaryFieldId(undefined);
|
||||
const newTableId = value as string;
|
||||
setPrimaryTableId(newTableId);
|
||||
if (
|
||||
newTableId !==
|
||||
preSelectedSourceTableId
|
||||
) {
|
||||
setPrimaryFieldId(undefined);
|
||||
}
|
||||
}}
|
||||
emptyPlaceholder={t(
|
||||
'create_relationship_dialog.no_tables_found'
|
||||
@@ -253,6 +281,8 @@ export const CreateRelationshipDialog: React.FC<
|
||||
'create_relationship_dialog.primary_field_placeholder'
|
||||
)}
|
||||
value={primaryFieldId}
|
||||
open={primaryFieldSelectOpen}
|
||||
onOpenChange={setPrimaryFieldSelectOpen}
|
||||
onChange={(value) =>
|
||||
setPrimaryFieldId(value as string)
|
||||
}
|
||||
@@ -283,6 +313,8 @@ export const CreateRelationshipDialog: React.FC<
|
||||
'create_relationship_dialog.referenced_table_placeholder'
|
||||
)}
|
||||
value={referencedTableId}
|
||||
open={referencedTableSelectOpen}
|
||||
onOpenChange={setReferencedTableSelectOpen}
|
||||
onChange={(value) => {
|
||||
setReferencedTableId(value as string);
|
||||
setReferencedFieldId(undefined);
|
||||
|
||||
@@ -402,6 +402,7 @@ export const ar: LanguageTranslation = {
|
||||
edit_table: 'تعديل الجدول',
|
||||
duplicate_table: 'نسخ الجدول',
|
||||
delete_table: 'حذف الجدول',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: '({{key}} مغنظة الشبكة (اضغط مع الاستمرار على',
|
||||
|
||||
@@ -406,6 +406,7 @@ export const bn: LanguageTranslation = {
|
||||
edit_table: 'টেবিল সম্পাদনা করুন',
|
||||
duplicate_table: 'টেবিল নকল করুন',
|
||||
delete_table: 'টেবিল মুছে ফেলুন',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: 'গ্রিডে স্ন্যাপ করুন (অবস্থান {{key}})',
|
||||
|
||||
@@ -409,6 +409,7 @@ export const de: LanguageTranslation = {
|
||||
edit_table: 'Tabelle bearbeiten',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: 'Tabelle löschen',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Add translations
|
||||
|
||||
@@ -401,6 +401,7 @@ export const en = {
|
||||
edit_table: 'Edit Table',
|
||||
duplicate_table: 'Duplicate Table',
|
||||
delete_table: 'Delete Table',
|
||||
add_relationship: 'Add Relationship',
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: 'Snap to Grid (Hold {{key}})',
|
||||
|
||||
@@ -408,6 +408,7 @@ export const es: LanguageTranslation = {
|
||||
edit_table: 'Editar Tabla',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: 'Eliminar Tabla',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Add translations
|
||||
|
||||
@@ -410,6 +410,7 @@ export const fr: LanguageTranslation = {
|
||||
edit_table: 'Éditer la Table',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: 'Supprimer la Table',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Add translations
|
||||
|
||||
@@ -406,6 +406,7 @@ export const gu: LanguageTranslation = {
|
||||
edit_table: 'ટેબલ સંપાદિત કરો',
|
||||
duplicate_table: 'ટેબલ નકલ કરો',
|
||||
delete_table: 'ટેબલ કાઢી નાખો',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: 'ગ્રિડ પર સ્નેપ કરો (જમાવટ {{key}})',
|
||||
|
||||
@@ -410,6 +410,7 @@ export const hi: LanguageTranslation = {
|
||||
edit_table: 'तालिका संपादित करें',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: 'तालिका हटाएँ',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Add translations
|
||||
|
||||
@@ -405,6 +405,7 @@ export const id_ID: LanguageTranslation = {
|
||||
edit_table: 'Ubah Tabel',
|
||||
delete_table: 'Hapus Tabel',
|
||||
duplicate_table: 'Duplikat Tabel',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: 'Snap ke Kisi (Tahan {{key}})',
|
||||
|
||||
@@ -413,6 +413,7 @@ export const ja: LanguageTranslation = {
|
||||
edit_table: 'テーブルを編集',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: 'テーブルを削除',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Add translations
|
||||
|
||||
@@ -402,6 +402,7 @@ export const ko_KR: LanguageTranslation = {
|
||||
edit_table: '테이블 수정',
|
||||
duplicate_table: '테이블 복제',
|
||||
delete_table: '테이블 삭제',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: '그리드에 맞추기 ({{key}}를 누른채 유지)',
|
||||
|
||||
@@ -414,8 +414,8 @@ export const mr: LanguageTranslation = {
|
||||
table_node_context_menu: {
|
||||
edit_table: 'टेबल संपादित करा',
|
||||
delete_table: 'टेबल हटवा',
|
||||
// TODO: Add translations
|
||||
duplicate_table: 'Duplicate Table',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Add translations
|
||||
|
||||
@@ -408,6 +408,7 @@ export const ne: LanguageTranslation = {
|
||||
edit_table: 'तालिका सम्पादन गर्नुहोस्',
|
||||
duplicate_table: 'तालिका नक्कली गर्नुहोस्',
|
||||
delete_table: 'तालिका हटाउनुहोस्',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: 'ग्रिडमा स्न्याप गर्नुहोस् ({{key}} थिच्नुहोस)',
|
||||
|
||||
@@ -407,6 +407,7 @@ export const pt_BR: LanguageTranslation = {
|
||||
edit_table: 'Editar Tabela',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: 'Excluir Tabela',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Add translations
|
||||
|
||||
@@ -403,6 +403,7 @@ export const ru: LanguageTranslation = {
|
||||
edit_table: 'Изменить таблицу',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: 'Удалить таблицу',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
copy_to_clipboard: 'Скопировать в буфер обмена',
|
||||
|
||||
@@ -409,9 +409,9 @@ export const te: LanguageTranslation = {
|
||||
|
||||
table_node_context_menu: {
|
||||
edit_table: 'పట్టికను సవరించు',
|
||||
// TODO: Translate
|
||||
duplicate_table: 'Duplicate Table',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: 'పట్టికను తొలగించు',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Translate
|
||||
|
||||
@@ -394,8 +394,8 @@ export const tr: LanguageTranslation = {
|
||||
table_node_context_menu: {
|
||||
edit_table: 'Tabloyu Düzenle',
|
||||
delete_table: 'Tabloyu Sil',
|
||||
// TODO: Translate
|
||||
duplicate_table: 'Duplicate Table',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
// TODO: Translate
|
||||
|
||||
@@ -402,6 +402,7 @@ export const uk: LanguageTranslation = {
|
||||
edit_table: 'Редагувати таблицю',
|
||||
duplicate_table: 'Дублювати таблицю',
|
||||
delete_table: 'Видалити таблицю',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: 'Вирівнювати за сіткою (Отримуйте {{key}})',
|
||||
|
||||
@@ -403,6 +403,7 @@ export const vi: LanguageTranslation = {
|
||||
edit_table: 'Sửa bảng',
|
||||
duplicate_table: 'Nhân đôi bảng',
|
||||
delete_table: 'Xóa bảng',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: 'Căn lưới (Giữ phím {{key}})',
|
||||
|
||||
@@ -399,6 +399,7 @@ export const zh_CN: LanguageTranslation = {
|
||||
edit_table: '编辑表',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: '删除表',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: '对齐到网格(按住 {{key}})',
|
||||
|
||||
@@ -398,6 +398,7 @@ export const zh_TW: LanguageTranslation = {
|
||||
edit_table: '編輯表格',
|
||||
duplicate_table: 'Duplicate Table', // TODO: Translate
|
||||
delete_table: '刪除表格',
|
||||
add_relationship: 'Add Relationship', // TODO: Translate
|
||||
},
|
||||
|
||||
snap_to_grid_tooltip: '對齊網格(按住 {{key}})',
|
||||
|
||||
@@ -9,9 +9,10 @@ import { useChartDB } from '@/hooks/use-chartdb';
|
||||
import { useLayout } from '@/hooks/use-layout';
|
||||
import { cloneTable } from '@/lib/clone';
|
||||
import type { DBTable } from '@/lib/domain/db-table';
|
||||
import { Copy, Pencil, Trash2 } from 'lucide-react';
|
||||
import { Copy, Pencil, Trash2, Workflow } from 'lucide-react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDialog } from '@/hooks/use-dialog';
|
||||
|
||||
export interface TableNodeContextMenuProps {
|
||||
table: DBTable;
|
||||
@@ -24,6 +25,7 @@ export const TableNodeContextMenu: React.FC<
|
||||
const { openTableFromSidebar } = useLayout();
|
||||
const { t } = useTranslation();
|
||||
const { isMd: isDesktop } = useBreakpoint('md');
|
||||
const { openCreateRelationshipDialog } = useDialog();
|
||||
|
||||
const duplicateTableHandler = useCallback(() => {
|
||||
const clonedTable = cloneTable(table);
|
||||
@@ -43,6 +45,12 @@ export const TableNodeContextMenu: React.FC<
|
||||
removeTable(table.id);
|
||||
}, [removeTable, table.id]);
|
||||
|
||||
const addRelationshipHandler = useCallback(() => {
|
||||
openCreateRelationshipDialog({
|
||||
sourceTableId: table.id,
|
||||
});
|
||||
}, [openCreateRelationshipDialog, table.id]);
|
||||
|
||||
if (!isDesktop || readonly) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
@@ -64,6 +72,13 @@ export const TableNodeContextMenu: React.FC<
|
||||
<span>{t('table_node_context_menu.duplicate_table')}</span>
|
||||
<Copy className="size-3.5" />
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem
|
||||
onClick={addRelationshipHandler}
|
||||
className="flex justify-between gap-3"
|
||||
>
|
||||
<span>{t('table_node_context_menu.add_relationship')}</span>
|
||||
<Workflow className="size-3.5" />
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem
|
||||
onClick={removeTableHandler}
|
||||
className="flex justify-between gap-3"
|
||||
|
||||
Reference in New Issue
Block a user