fix(relationships): add locate and switch tables actions for FKs

This commit is contained in:
johnnyfish
2026-01-05 21:52:56 +02:00
parent 6879e19fa5
commit 7c59b9ffef
26 changed files with 85 additions and 22 deletions

View File

@@ -201,6 +201,7 @@ export const ar: LanguageTranslation = {
delete_relationship: 'حذف',
relationship_actions: {
title: 'إجراءات',
switch_tables: 'تبديل الجداول',
delete_relationship: 'حذف',
},
},

View File

@@ -203,6 +203,7 @@ export const bn: LanguageTranslation = {
delete_relationship: 'মুছুন',
relationship_actions: {
title: 'কর্ম',
switch_tables: 'টেবিল পরিবর্তন করুন',
delete_relationship: 'মুছুন',
},
},

View File

@@ -203,6 +203,7 @@ export const de: LanguageTranslation = {
delete_relationship: 'Löschen',
relationship_actions: {
title: 'Aktionen',
switch_tables: 'Tabellen tauschen',
delete_relationship: 'Löschen',
},
},

View File

@@ -197,6 +197,7 @@ export const en = {
delete_relationship: 'Delete',
relationship_actions: {
title: 'Actions',
switch_tables: 'Switch Tables',
delete_relationship: 'Delete',
},
},

View File

@@ -202,6 +202,7 @@ export const es: LanguageTranslation = {
delete_relationship: 'Eliminar',
relationship_actions: {
title: 'Acciones',
switch_tables: 'Intercambiar Tablas',
delete_relationship: 'Eliminar',
},
},

View File

@@ -200,6 +200,7 @@ export const fr: LanguageTranslation = {
delete_relationship: 'Supprimer',
relationship_actions: {
title: 'Actions',
switch_tables: 'Inverser les Tables',
delete_relationship: 'Supprimer',
},
},

View File

@@ -204,6 +204,7 @@ export const gu: LanguageTranslation = {
delete_relationship: 'કાઢી નાખો',
relationship_actions: {
title: 'ક્રિયાઓ',
switch_tables: 'ટેબલ્સ બદલો',
delete_relationship: 'કાઢી નાખો',
},
},

View File

@@ -203,6 +203,7 @@ export const hi: LanguageTranslation = {
delete_relationship: 'हटाएँ',
relationship_actions: {
title: 'क्रियाएँ',
switch_tables: 'टेबल्स बदलें',
delete_relationship: 'हटाएँ',
},
},

View File

@@ -198,6 +198,7 @@ export const hr: LanguageTranslation = {
delete_relationship: 'Izbriši',
relationship_actions: {
title: 'Radnje',
switch_tables: 'Zamijeni Tablice',
delete_relationship: 'Izbriši',
},
},

View File

@@ -202,6 +202,7 @@ export const id_ID: LanguageTranslation = {
delete_relationship: 'Hapus',
relationship_actions: {
title: 'Aksi',
switch_tables: 'Tukar Tabel',
delete_relationship: 'Hapus',
},
},

View File

@@ -205,6 +205,7 @@ export const ja: LanguageTranslation = {
delete_relationship: '削除',
relationship_actions: {
title: '操作',
switch_tables: 'テーブルを入れ替え',
delete_relationship: '削除',
},
},

View File

@@ -202,6 +202,7 @@ export const ko_KR: LanguageTranslation = {
delete_relationship: '제거',
relationship_actions: {
title: '연관 관계 작업',
switch_tables: '테이블 전환',
delete_relationship: '연관 관계 삭제',
},
},

View File

@@ -206,6 +206,7 @@ export const mr: LanguageTranslation = {
delete_relationship: 'हटवा',
relationship_actions: {
title: 'क्रिया',
switch_tables: 'सारण्या बदला',
delete_relationship: 'हटवा',
},
},

View File

@@ -203,6 +203,7 @@ export const ne: LanguageTranslation = {
delete_relationship: 'हटाउनुहोस्',
relationship_actions: {
title: 'कार्यहरू',
switch_tables: 'तालिकाहरू स्विच गर्नुहोस्',
delete_relationship: 'हटाउनुहोस्',
},
},

View File

@@ -203,6 +203,7 @@ export const pt_BR: LanguageTranslation = {
delete_relationship: 'Excluir',
relationship_actions: {
title: 'Ações',
switch_tables: 'Trocar Tabelas',
delete_relationship: 'Excluir',
},
},

View File

@@ -199,6 +199,7 @@ export const ru: LanguageTranslation = {
delete_relationship: 'Удалить',
relationship_actions: {
title: 'Действия',
switch_tables: 'Поменять таблицы',
delete_relationship: 'Удалить',
},
},

View File

@@ -204,6 +204,7 @@ export const te: LanguageTranslation = {
delete_relationship: 'సంబంధం తొలగించు',
relationship_actions: {
title: 'చర్యలు',
switch_tables: 'టేబుల్‌లను మార్చు',
delete_relationship: 'సంబంధం తొలగించు',
},
},

View File

@@ -203,6 +203,7 @@ export const tr: LanguageTranslation = {
delete_relationship: 'Sil',
relationship_actions: {
title: 'İşlemler',
switch_tables: 'Tabloları Değiştir',
delete_relationship: 'Sil',
},
},

View File

@@ -201,6 +201,7 @@ export const uk: LanguageTranslation = {
delete_relationship: 'Видалити',
relationship_actions: {
title: 'Дії',
switch_tables: 'Поміняти таблиці',
delete_relationship: 'Видалити',
},
},

View File

@@ -202,6 +202,7 @@ export const vi: LanguageTranslation = {
delete_relationship: 'Xóa',
relationship_actions: {
title: 'Hành động',
switch_tables: 'Đổi Bảng',
delete_relationship: 'Xóa',
},
},

View File

@@ -199,6 +199,7 @@ export const zh_CN: LanguageTranslation = {
delete_relationship: '删除',
relationship_actions: {
title: '操作',
switch_tables: '交换表',
delete_relationship: '删除',
},
},

View File

@@ -199,6 +199,7 @@ export const zh_TW: LanguageTranslation = {
delete_relationship: '刪除',
relationship_actions: {
title: '操作',
switch_tables: '交換表',
delete_relationship: '刪除',
},
},

View File

@@ -1,5 +1,5 @@
import React, { useRef } from 'react';
import { Trash2, ArrowLeftRight } from 'lucide-react';
import { Trash2, ArrowLeftRight, CircleDotDashed } from 'lucide-react';
import { Button } from '@/components/button/button';
import type { Cardinality } from '@/lib/domain/db-relationship';
import { cn } from '@/lib/utils';
@@ -16,6 +16,7 @@ export interface EditRelationshipPopoverProps {
) => void;
onSwitch: () => void;
onDelete: () => void;
onLocate: () => void;
}
type RelationshipTypeOption = {
@@ -39,6 +40,7 @@ export const EditRelationshipPopover: React.FC<
onCardinalityChange,
onSwitch,
onDelete,
onLocate,
}) => {
const popoverRef = useRef<HTMLDivElement>(null);
const { closeRelationshipPopover } = useCanvas();
@@ -55,6 +57,20 @@ export const EditRelationshipPopover: React.FC<
}}
>
<div className="flex items-center gap-1">
<Button
variant="ghost"
size="sm"
className="size-7 p-0 text-slate-600 hover:bg-slate-100 hover:text-slate-700"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onLocate();
}}
title="Locate in side panel"
>
<CircleDotDashed className="!size-3.5" />
</Button>
<div className="mx-1 h-6 w-px bg-slate-300" />
{relationshipTypes.map((type) => {
const isActive =
type.sourceCardinality === sourceCardinality &&

View File

@@ -10,6 +10,7 @@ import { getCardinalityMarkerId } from '../canvas-utils';
import { useDiff } from '@/context/diff-context/use-diff';
import { useLocalConfig } from '@/hooks/use-local-config';
import { useCanvas } from '@/hooks/use-canvas';
import { useLayout } from '@/hooks/use-layout';
import { EditRelationshipPopover } from './edit-relationship-popover';
import { EllipsisIcon } from 'lucide-react';
@@ -46,6 +47,7 @@ export const RelationshipEdge: React.FC<EdgeProps<RelationshipEdgeType>> =
openRelationshipPopover,
closeRelationshipPopover,
} = useCanvas();
const { openRelationshipFromSidebar } = useLayout();
const relationship = data?.relationship;
@@ -138,6 +140,11 @@ export const RelationshipEdge: React.FC<EdgeProps<RelationshipEdgeType>> =
closeRelationshipPopover();
}, [id, removeRelationship, closeRelationshipPopover]);
const handleLocate = useCallback(() => {
openRelationshipFromSidebar(id);
closeRelationshipPopover();
}, [id, openRelationshipFromSidebar, closeRelationshipPopover]);
const edgeNumber = useMemo(() => {
let index = 0;
for (const rel of relationships) {
@@ -380,6 +387,7 @@ export const RelationshipEdge: React.FC<EdgeProps<RelationshipEdgeType>> =
onCardinalityChange={handleCardinalityChange}
onSwitch={handleSwitchTables}
onDelete={handleDelete}
onLocate={handleLocate}
/>,
document.body
)}

View File

@@ -22,12 +22,7 @@ import {
determineRelationshipType,
} from '@/lib/domain/db-relationship';
import { useReactFlow } from '@xyflow/react';
import {
FileMinus2,
FileOutput,
Trash2,
ChevronsLeftRightEllipsis,
} from 'lucide-react';
import { Trash2, ChevronsLeftRightEllipsis } from 'lucide-react';
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -92,13 +87,8 @@ export const RelationshipListItemContent: React.FC<
<div className="flex flex-col gap-6">
<div className="flex items-center justify-between gap-1 text-xs">
<div className="flex basis-1/2 flex-col gap-2 overflow-hidden text-xs">
<div className="flex flex-row items-center gap-1">
<FileOutput className="size-4 text-subtitle" />
<div className="font-bold text-subtitle">
{t(
'side_panel.refs_section.relationship.primary'
)}
</div>
<div className="font-bold text-subtitle">
{t('side_panel.refs_section.relationship.primary')}
</div>
<Tooltip>
<TooltipTrigger>
@@ -118,13 +108,8 @@ export const RelationshipListItemContent: React.FC<
</Tooltip>
</div>
<div className="flex basis-1/2 flex-col gap-2 overflow-hidden text-xs">
<div className="flex flex-row items-center gap-1">
<FileMinus2 className="size-4 text-subtitle" />
<div className="font-bold text-subtitle">
{t(
'side_panel.refs_section.relationship.foreign'
)}
</div>
<div className="font-bold text-subtitle">
{t('side_panel.refs_section.relationship.foreign')}
</div>
<Tooltip>
<TooltipTrigger>

View File

@@ -5,6 +5,7 @@ import {
CircleDotDashed,
Trash2,
Check,
ArrowLeftRight,
} from 'lucide-react';
import { ListItemHeaderButton } from '../../../../list-item-header-button/list-item-header-button';
import type { DBRelationship } from '@/lib/domain/db-relationship';
@@ -92,6 +93,25 @@ export const RelationshipListItemHeader: React.FC<
});
}, [relationship.id, removeRelationship, deleteElements]);
const switchTablesHandler = useCallback(
(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
e.stopPropagation();
updateRelationship(
relationship.id,
{
sourceTableId: relationship.targetTableId,
targetTableId: relationship.sourceTableId,
sourceFieldId: relationship.targetFieldId,
targetFieldId: relationship.sourceFieldId,
sourceCardinality: relationship.targetCardinality,
targetCardinality: relationship.sourceCardinality,
},
{ updateHistory: true }
);
},
[relationship, updateRelationship]
);
const renderDropDownMenu = useCallback(
() => (
<DropdownMenu>
@@ -107,6 +127,18 @@ export const RelationshipListItemHeader: React.FC<
)}
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem
onClick={switchTablesHandler}
className="flex justify-between"
>
{t(
'side_panel.refs_section.relationship.relationship_actions.switch_tables'
)}
<ArrowLeftRight className="size-3.5" />
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem
onClick={deleteRelationshipHandler}
@@ -121,7 +153,7 @@ export const RelationshipListItemHeader: React.FC<
</DropdownMenuContent>
</DropdownMenu>
),
[deleteRelationshipHandler, t]
[deleteRelationshipHandler, switchTablesHandler, t]
);
return (