diff --git a/src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts b/src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts index 0f8b8de8..4f9c0b18 100644 --- a/src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts +++ b/src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts @@ -65,6 +65,11 @@ export interface CanvasSchemaContextVm { updateTablePosition: UpdatePositionFn; doFieldToggleCollapse: (tableId: string, fieldId: GUID) => void; updateFullTable: (table: TableVm) => void; + updateTableSingleField: ( + table: TableVm, + fieldName: string, + fieldValue: string + ) => void; addTable: (table: TableVm) => void; addRelation: (relation: RelationVm) => void; doSelectElement: (id: GUID | null) => void; diff --git a/src/core/providers/canvas-schema/canvas-schema.business.ts b/src/core/providers/canvas-schema/canvas-schema.business.ts index ec255ef2..8a3c4d8f 100644 --- a/src/core/providers/canvas-schema/canvas-schema.business.ts +++ b/src/core/providers/canvas-schema/canvas-schema.business.ts @@ -86,6 +86,24 @@ export const updateTable = ( } }); +export const updateTableField = ( + table: TableVm, + fieldName: string, + fieldValue: string, + dbSchema: DatabaseSchemaVm +): DatabaseSchemaVm => + produce(dbSchema, draft => { + const tableIndex = draft.tables.findIndex(t => t.id === table.id); + + if (tableIndex !== -1) { + if (fieldName === 'tableName') { + draft.tables[tableIndex].tableName = fieldValue; + } + + //TODO: Implement update for other fields + } + }); + export const addNewTable = ( table: TableVm, databaseSchema: DatabaseSchemaVm diff --git a/src/core/providers/canvas-schema/canvas-schema.provider.tsx b/src/core/providers/canvas-schema/canvas-schema.provider.tsx index c19e9788..a5ff80de 100644 --- a/src/core/providers/canvas-schema/canvas-schema.provider.tsx +++ b/src/core/providers/canvas-schema/canvas-schema.provider.tsx @@ -19,6 +19,7 @@ import { addNewTable, updateRelation, updateTable, + updateTableField, } from './canvas-schema.business'; import { useHistoryManager } from '@/common/undo-redo'; import { mapSchemaToLatestVersion } from './canvas-schema.mapper'; @@ -58,6 +59,16 @@ export const CanvasSchemaProvider: React.FC = props => { setSchema(prevSchema => updateTable(table, prevSchema)); }; + const updateTableSingleField = ( + table: TableVm, + fieldName: string, + fieldValue: string + ) => { + setSchema(prevSchema => + updateTableField(table, fieldName, fieldValue, prevSchema) + ); + }; + // TODO: #56 created to track this // https://github.com/Lemoncode/mongo-modeler/issues/56 const addTable = (table: TableVm) => { @@ -145,6 +156,7 @@ export const CanvasSchemaProvider: React.FC = props => { updateTablePosition, doFieldToggleCollapse, updateFullTable, + updateTableSingleField, addTable, addRelation, doSelectElement, diff --git a/src/core/providers/table-provider/index.ts b/src/core/providers/table-provider/index.ts new file mode 100644 index 00000000..9c200c35 --- /dev/null +++ b/src/core/providers/table-provider/index.ts @@ -0,0 +1,2 @@ +export * from './table.context'; +export * from './table.provider'; diff --git a/src/core/providers/table-provider/table.context.tsx b/src/core/providers/table-provider/table.context.tsx new file mode 100644 index 00000000..8c98d85d --- /dev/null +++ b/src/core/providers/table-provider/table.context.tsx @@ -0,0 +1,4 @@ +import { createContext } from 'react'; +import { TableContextModel } from './table.model'; + +export const TableContext = createContext(null); diff --git a/src/core/providers/table-provider/table.model.tsx b/src/core/providers/table-provider/table.model.tsx new file mode 100644 index 00000000..9fff888f --- /dev/null +++ b/src/core/providers/table-provider/table.model.tsx @@ -0,0 +1,4 @@ +export interface TableContextModel { + isTitleInEditMode: boolean; + setIsTitleInEditMode: (isInEditMode: boolean) => void; +} diff --git a/src/core/providers/table-provider/table.provider.tsx b/src/core/providers/table-provider/table.provider.tsx new file mode 100644 index 00000000..d25a22bc --- /dev/null +++ b/src/core/providers/table-provider/table.provider.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { TableContext } from './table.context'; + +interface Props { + children: React.ReactNode; +} + +export const TableProvider: React.FC = props => { + const { children } = props; + const [isTitleInEditMode, setIsTitleInEditMode] = + React.useState(false); + + return ( + + {children} + + ); +}; + +export const useTableContext = () => { + const context = React.useContext(TableContext); + if (context === null) { + throw new Error( + 'useTableContext: Ensure you have wrapped your Table with TableContext.Provider' + ); + } + + return context; +}; diff --git a/src/pods/canvas/canvas.pod.tsx b/src/pods/canvas/canvas.pod.tsx index 654f2316..c88ffd17 100644 --- a/src/pods/canvas/canvas.pod.tsx +++ b/src/pods/canvas/canvas.pod.tsx @@ -33,7 +33,6 @@ export const CanvasPod: React.FC = () => { updateFullRelation, doUndo, doRedo, - deleteSelectedItem, loadSchema, } = useCanvasSchemaContext(); const { canvasViewSettings, setScrollPosition, setLoadSample } = @@ -144,12 +143,6 @@ export const CanvasPod: React.FC = () => { if (e.metaKey && e.shiftKey && e.key === 'z') { doRedo(); } - - if (e.key === 'Delete' || e.key === 'Backspace') { - if (canvasSchema.selectedElementId) { - deleteSelectedItem(canvasSchema.selectedElementId); - } - } }; modalDialog.isOpen diff --git a/src/pods/canvas/components/table/components/database-table-header.component.tsx b/src/pods/canvas/components/table/components/database-table-header.component.tsx index 08b1c5d9..50aa90a4 100644 --- a/src/pods/canvas/components/table/components/database-table-header.component.tsx +++ b/src/pods/canvas/components/table/components/database-table-header.component.tsx @@ -1,5 +1,5 @@ import { Edit } from '@/common/components'; -import { TABLE_CONST } from '@/core/providers'; +import { TABLE_CONST, TableVm } from '@/core/providers'; import { TruncatedText } from './truncated-text.component'; import { PENCIL_ICON_HEIGHT, @@ -9,23 +9,27 @@ import { TITLE_MARGIN_LEFT, } from '../database-table.const'; import classes from '../database-table.module.css'; +import { useTableContext } from '@/core/providers/table-provider'; +import { useEffect } from 'react'; interface Props { onEditTable: () => void; isSelected: boolean; + table: TableVm; tableName: string; onSelectTable: () => void; - isTabletOrMobileDevice: boolean; + isEditingTitle?: boolean; } export const DatabaseTableHeader: React.FC = props => { - const { - onEditTable, - isSelected, - tableName, - onSelectTable, - isTabletOrMobileDevice, - } = props; + const { isTitleInEditMode, setIsTitleInEditMode } = useTableContext(); + const { onEditTable, isSelected, tableName, onSelectTable, table } = props; + + useEffect(() => { + if (!isSelected) { + setIsTitleInEditMode(false); + } + }, [isSelected, setIsTitleInEditMode]); const handlePencilIconClick = ( e: React.MouseEvent @@ -39,9 +43,8 @@ export const DatabaseTableHeader: React.FC = props => { e.stopPropagation(); }; - const handleDoubleClick = (e: React.MouseEvent) => { - onEditTable(); - e.stopPropagation(); + const handleDoubleClick = () => { + setIsTitleInEditMode(true); }; return ( @@ -65,13 +68,18 @@ export const DatabaseTableHeader: React.FC = props => { /> - {isSelected && !isTabletOrMobileDevice && ( + {isSelected && ( void; + table?: TableVm; x: number; y: number; width: number; height: number; textClass?: string; + isTextInEditMode?: boolean; } export const TruncatedText: React.FC = props => { const id = React.useMemo(() => GenerateGUID(), []); - const { text, x, y, width, height, textClass } = props; + const { text, table, x, y, width, height, textClass, isTextInEditMode } = + props; + const inputRef = useRef(null); + const [editableText, setEditableText] = useState(text); + const { updateTableSingleField } = useCanvasSchemaContext(); + const { setIsTitleInEditMode } = useTableContext(); + + const handleInputChange = () => { + if (inputRef.current) { + if (table) { + updateTableSingleField(table, 'tableName', inputRef.current.value); + } + setEditableText(inputRef.current.value); + } + }; + + useEffect(() => { + if (isTextInEditMode && inputRef.current) { + inputRef.current.focus(); + } + }, [isTextInEditMode]); + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + if (inputRef.current) { + setIsTitleInEditMode(false); + } + } + }; return ( <> - - - {text} - + {isTextInEditMode ? ( + + + + ) : ( + + {text} + + )} ); }; diff --git a/src/pods/canvas/components/table/database-table.component.tsx b/src/pods/canvas/components/table/database-table.component.tsx index 1fbd90a9..1d0c1f48 100644 --- a/src/pods/canvas/components/table/database-table.component.tsx +++ b/src/pods/canvas/components/table/database-table.component.tsx @@ -11,6 +11,7 @@ import { } from './components'; import { renderRows } from './database-table-render-rows.helper'; import classes from './database-table.module.css'; +import { TableProvider } from '@/core/providers/table-provider'; // TODO: We should add an optional field to indicate FONT_SIZE in case we override the standard class // TODO: There's is a solution more elaborated (using JS) to show elipsis ... if text is too long @@ -33,10 +34,8 @@ export const DatabaseTable: React.FC = ({ canvasSize, isSelected, selectTable, - isTabletOrMobileDevice, }) => { const rowHeight = TABLE_CONST.FONT_SIZE + TABLE_CONST.ROW_PADDING; - const [renderedRows, totalHeight] = React.useMemo((): [ JSX.Element[], number, @@ -76,22 +75,27 @@ export const DatabaseTable: React.FC = ({ }; return ( - | undefined} - > - - - - + + | undefined} + > + + + + + ); }; diff --git a/src/pods/toolbar/shortcut/shortcut.const.ts b/src/pods/toolbar/shortcut/shortcut.const.ts index 5e0195b4..6207ed44 100644 --- a/src/pods/toolbar/shortcut/shortcut.const.ts +++ b/src/pods/toolbar/shortcut/shortcut.const.ts @@ -20,7 +20,7 @@ export const SHORTCUTS: Shortcut = { delete: { description: 'Delete', id: 'delete-button-shortcut', - targetKey: ['backspace'], + targetKey: ['Backspace'], targetKeyLabel: 'Backspace', }, export: {