From 44cf5ca264f52851f2dffb51a752a52b6fa7ec8d Mon Sep 17 00:00:00 2001 From: Guy Ben-Aharon Date: Thu, 14 Nov 2024 17:35:53 +0200 Subject: [PATCH] feat(duplicate table): duplicate table from the canvas and sidebar (#404) * feat(duplicate table): duplicate table from the canvas and sidebar * feat(duplicate table): underscore instead of space * feat(duplicate table): underscore instead of space --- src/i18n/locales/de.ts | 2 + src/i18n/locales/en.ts | 2 + src/i18n/locales/es.ts | 2 + src/i18n/locales/fr.ts | 2 + src/i18n/locales/hi.ts | 2 + src/i18n/locales/ja.ts | 2 + src/i18n/locales/ko_KR.ts | 2 + src/i18n/locales/pt_BR.ts | 2 + src/i18n/locales/ru.ts | 2 + src/i18n/locales/uk.ts | 2 + src/i18n/locales/zh_CN.ts | 2 + src/i18n/locales/zh_TW.ts | 2 + .../table-node/table-node-context-menu.tsx | 37 ++++++++++++++++--- .../table-list-item-header.tsx | 30 +++++++++++++++ 14 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts index 954d5fc37..6a2f20b0e 100644 --- a/src/i18n/locales/de.ts +++ b/src/i18n/locales/de.ts @@ -145,6 +145,7 @@ export const de: LanguageTranslation = { change_schema: 'Schema ändern', add_field: 'Feld hinzufügen', add_index: 'Index hinzufügen', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Tabelle löschen', }, }, @@ -371,6 +372,7 @@ export const de: LanguageTranslation = { table_node_context_menu: { edit_table: 'Tabelle bearbeiten', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Tabelle löschen', }, diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 20336f8c1..9caf8069b 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -144,6 +144,7 @@ export const en = { change_schema: 'Change Schema', add_field: 'Add Field', add_index: 'Add Index', + duplicate_table: 'Duplicate Table', delete_table: 'Delete Table', }, }, @@ -367,6 +368,7 @@ export const en = { table_node_context_menu: { edit_table: 'Edit Table', + duplicate_table: 'Duplicate Table', delete_table: 'Delete Table', }, diff --git a/src/i18n/locales/es.ts b/src/i18n/locales/es.ts index 7652385ff..7a7e7e55f 100644 --- a/src/i18n/locales/es.ts +++ b/src/i18n/locales/es.ts @@ -136,6 +136,7 @@ export const es: LanguageTranslation = { change_schema: 'Cambiar Esquema', add_field: 'Agregar Campo', add_index: 'Agregar Índice', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Eliminar Tabla', }, }, @@ -371,6 +372,7 @@ export const es: LanguageTranslation = { table_node_context_menu: { edit_table: 'Editar Tabla', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Eliminar Tabla', }, diff --git a/src/i18n/locales/fr.ts b/src/i18n/locales/fr.ts index b77059a8e..0264e1bf5 100644 --- a/src/i18n/locales/fr.ts +++ b/src/i18n/locales/fr.ts @@ -135,6 +135,7 @@ export const fr: LanguageTranslation = { title: 'Actions de la Table', add_field: 'Ajouter un Champ', add_index: 'Ajouter un Index', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Supprimer la Table', change_schema: 'Changer le Schéma', }, @@ -373,6 +374,7 @@ export const fr: LanguageTranslation = { table_node_context_menu: { edit_table: 'Éditer la Table', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Supprimer la Table', }, diff --git a/src/i18n/locales/hi.ts b/src/i18n/locales/hi.ts index 52b487d1d..d992afcd6 100644 --- a/src/i18n/locales/hi.ts +++ b/src/i18n/locales/hi.ts @@ -146,6 +146,7 @@ export const hi: LanguageTranslation = { change_schema: 'स्कीमा बदलें', add_field: 'फ़ील्ड जोड़ें', add_index: 'सूचकांक जोड़ें', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'तालिका हटाएँ', }, }, @@ -373,6 +374,7 @@ export const hi: LanguageTranslation = { table_node_context_menu: { edit_table: 'तालिका संपादित करें', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'तालिका हटाएँ', }, diff --git a/src/i18n/locales/ja.ts b/src/i18n/locales/ja.ts index 002fcc40d..55125177a 100644 --- a/src/i18n/locales/ja.ts +++ b/src/i18n/locales/ja.ts @@ -147,6 +147,7 @@ export const ja: LanguageTranslation = { change_schema: 'スキーマを変更', add_field: 'フィールドを追加', add_index: 'インデックスを追加', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'テーブルを削除', }, }, @@ -375,6 +376,7 @@ export const ja: LanguageTranslation = { table_node_context_menu: { edit_table: 'テーブルを編集', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'テーブルを削除', }, diff --git a/src/i18n/locales/ko_KR.ts b/src/i18n/locales/ko_KR.ts index f60c1d130..2e25fdafa 100644 --- a/src/i18n/locales/ko_KR.ts +++ b/src/i18n/locales/ko_KR.ts @@ -145,6 +145,7 @@ export const ko_KR: LanguageTranslation = { change_schema: '스키마 변경', add_field: '필드 추가', add_index: '인덱스 추가', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: '테이블 삭제', }, }, @@ -369,6 +370,7 @@ export const ko_KR: LanguageTranslation = { table_node_context_menu: { edit_table: '테이블 수정', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: '테이블 삭제', }, diff --git a/src/i18n/locales/pt_BR.ts b/src/i18n/locales/pt_BR.ts index a27cfda47..60a21e465 100644 --- a/src/i18n/locales/pt_BR.ts +++ b/src/i18n/locales/pt_BR.ts @@ -145,6 +145,7 @@ export const pt_BR: LanguageTranslation = { change_schema: 'Alterar Esquema', add_field: 'Adicionar Campo', add_index: 'Adicionar Índice', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Excluir Tabela', }, }, @@ -370,6 +371,7 @@ export const pt_BR: LanguageTranslation = { table_node_context_menu: { edit_table: 'Editar Tabela', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Excluir Tabela', }, diff --git a/src/i18n/locales/ru.ts b/src/i18n/locales/ru.ts index e599ebd0e..6cd320f71 100644 --- a/src/i18n/locales/ru.ts +++ b/src/i18n/locales/ru.ts @@ -142,6 +142,7 @@ export const ru: LanguageTranslation = { change_schema: 'Изменить схему', add_field: 'Добавить поле', add_index: 'Добавить индекс', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Удалить таблицу', }, }, @@ -365,6 +366,7 @@ export const ru: LanguageTranslation = { table_node_context_menu: { edit_table: 'Изменить таблицу', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Удалить таблицу', }, diff --git a/src/i18n/locales/uk.ts b/src/i18n/locales/uk.ts index 963e31019..595a4261e 100644 --- a/src/i18n/locales/uk.ts +++ b/src/i18n/locales/uk.ts @@ -145,6 +145,7 @@ export const uk: LanguageTranslation = { change_schema: 'Змінити схему', add_field: 'Додати поле', add_index: 'Додати індекс', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Видалити таблицю', }, }, @@ -370,6 +371,7 @@ export const uk: LanguageTranslation = { table_node_context_menu: { edit_table: 'Редагувати таблицю', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: 'Видалити таблицю', }, diff --git a/src/i18n/locales/zh_CN.ts b/src/i18n/locales/zh_CN.ts index 6f4c7ee51..e47655be6 100644 --- a/src/i18n/locales/zh_CN.ts +++ b/src/i18n/locales/zh_CN.ts @@ -141,6 +141,7 @@ export const zh_CN: LanguageTranslation = { change_schema: '更改模式', add_field: '添加字段', add_index: '添加索引', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: '删除表', }, }, @@ -361,6 +362,7 @@ export const zh_CN: LanguageTranslation = { table_node_context_menu: { edit_table: '编辑表', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: '删除表', }, diff --git a/src/i18n/locales/zh_TW.ts b/src/i18n/locales/zh_TW.ts index 7c358d2e8..fd02c441d 100644 --- a/src/i18n/locales/zh_TW.ts +++ b/src/i18n/locales/zh_TW.ts @@ -141,6 +141,7 @@ export const zh_TW: LanguageTranslation = { change_schema: '變更 Schema', add_field: '新增欄位', add_index: '新增索引', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: '刪除表格', }, }, @@ -360,6 +361,7 @@ export const zh_TW: LanguageTranslation = { table_node_context_menu: { edit_table: '編輯表格', + duplicate_table: 'Duplicate Table', // TODO: Translate delete_table: '刪除表格', }, diff --git a/src/pages/editor-page/canvas/table-node/table-node-context-menu.tsx b/src/pages/editor-page/canvas/table-node/table-node-context-menu.tsx index c760295fd..5f8ce1bc4 100644 --- a/src/pages/editor-page/canvas/table-node/table-node-context-menu.tsx +++ b/src/pages/editor-page/canvas/table-node/table-node-context-menu.tsx @@ -7,7 +7,9 @@ import { import { useBreakpoint } from '@/hooks/use-breakpoint'; 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 React, { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -18,11 +20,21 @@ export interface TableNodeContextMenuProps { export const TableNodeContextMenu: React.FC< React.PropsWithChildren > = ({ children, table }) => { - const { removeTable, readonly } = useChartDB(); + const { removeTable, readonly, createTable } = useChartDB(); const { openTableFromSidebar } = useLayout(); const { t } = useTranslation(); const { isMd: isDesktop } = useBreakpoint('md'); + const duplicateTableHandler = useCallback(() => { + const clonedTable = cloneTable(table); + + clonedTable.name = `${clonedTable.name}_copy`; + clonedTable.x += 30; + clonedTable.y += 50; + + createTable(clonedTable); + }, [createTable, table]); + const editTableHandler = useCallback(() => { openTableFromSidebar(table.id); }, [openTableFromSidebar, table.id]); @@ -38,11 +50,26 @@ export const TableNodeContextMenu: React.FC< {children} - - {t('table_node_context_menu.edit_table')} + + {t('table_node_context_menu.edit_table')} + + + + {t('table_node_context_menu.duplicate_table')} + - - {t('table_node_context_menu.delete_table')} + + {t('table_node_context_menu.delete_table')} + diff --git a/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header.tsx b/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header.tsx index 9e4fc6bf4..989780d83 100644 --- a/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header.tsx +++ b/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header.tsx @@ -8,6 +8,7 @@ import { FileKey2, Check, Group, + Copy, } from 'lucide-react'; import { ListItemHeaderButton } from '@/pages/editor-page/side-panel/list-item-header-button/list-item-header-button'; import type { DBTable } from '@/lib/domain/db-table'; @@ -33,6 +34,7 @@ import { TooltipContent, TooltipTrigger, } from '@/components/tooltip/tooltip'; +import { cloneTable } from '@/lib/clone'; export interface TableListItemHeaderProps { table: DBTable; @@ -46,6 +48,7 @@ export const TableListItemHeader: React.FC = ({ removeTable, createIndex, createField, + createTable, schemas, filteredSchemas, } = useChartDB(); @@ -128,6 +131,20 @@ export const TableListItemHeader: React.FC = ({ }); }, [openTableSchemaDialog, table, schemas, updateTableSchema]); + const duplicateTableHandler = useCallback( + (e: React.MouseEvent) => { + e.stopPropagation(); + const clonedTable = cloneTable(table); + + clonedTable.name = `${clonedTable.name}_copy`; + clonedTable.x += 30; + clonedTable.y += 50; + + createTable(clonedTable); + }, + [createTable, table] + ); + const renderDropDownMenu = useCallback( () => ( @@ -189,6 +206,18 @@ export const TableListItemHeader: React.FC = ({ + + + {t( + 'side_panel.tables_section.table.table_actions.duplicate_table' + )} + + + + = ({ createField, createIndex, deleteTableHandler, + duplicateTableHandler, t, changeSchema, schemas.length,