From d71ba8addf41cca7bb4713ebde523392fe24c102 Mon Sep 17 00:00:00 2001 From: Jesus Sanz Date: Wed, 5 Feb 2025 18:39:37 +0100 Subject: [PATCH 1/2] Closes #539. Updated New Page functionality to clear the clipboard --- .../providers/canvas-schema/canvas-schema-vlatest.model.ts | 1 + src/core/providers/canvas-schema/canvas-schema.provider.tsx | 6 ++++++ .../toolbar/components/new-button/new-button.component.tsx | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) 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 45b0c6fd..0090999b 100644 --- a/src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts +++ b/src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts @@ -82,4 +82,5 @@ export interface CanvasSchemaContextVm { copySelectedTable: () => void; pasteTable: () => void; hasClipboardContent: boolean; + clearClipboard: () => void; } diff --git a/src/core/providers/canvas-schema/canvas-schema.provider.tsx b/src/core/providers/canvas-schema/canvas-schema.provider.tsx index 29767cba..e89d5d29 100644 --- a/src/core/providers/canvas-schema/canvas-schema.provider.tsx +++ b/src/core/providers/canvas-schema/canvas-schema.provider.tsx @@ -226,6 +226,11 @@ export const CanvasSchemaProvider: React.FC = props => { } }; + const clearClipboard = () => { + setClipboardTable(null); + setPasteOffset({ x: 0, y: 0 }); + }; + return ( = props => { copySelectedTable, pasteTable, hasClipboardContent: Boolean(clipboardTable), + clearClipboard, }} > {children} diff --git a/src/pods/toolbar/components/new-button/new-button.component.tsx b/src/pods/toolbar/components/new-button/new-button.component.tsx index 1f9d54a2..5b7ce903 100644 --- a/src/pods/toolbar/components/new-button/new-button.component.tsx +++ b/src/pods/toolbar/components/new-button/new-button.component.tsx @@ -8,13 +8,14 @@ import classes from '@/pods/toolbar/toolbar.pod.module.css'; import { SHORTCUTS } from '../../shortcut/shortcut.const'; export const NewButton = () => { - const { createEmptySchema } = useCanvasSchemaContext(); + const { createEmptySchema, clearClipboard } = useCanvasSchemaContext(); const { setFilename, setLoadSample } = useCanvasViewSettingsContext(); const handleNewButtonClick = () => { setFilename(''); createEmptySchema(); setLoadSample(false); + clearClipboard(); }; return ( From 953b9caab6aba6fa794993e59c18a66970f7920a Mon Sep 17 00:00:00 2001 From: Jesus Sanz Date: Fri, 18 Sep 2026 18:27:00 +0200 Subject: [PATCH 2/2] fix: clear clipboard when creating an empty schema --- .../canvas-schema-vlatest.model.ts | 1 - .../canvas-schema.provider.spec.tsx | 77 +++++++++++++++++++ .../canvas-schema/canvas-schema.provider.tsx | 2 +- .../new-button/new-button.component.tsx | 3 +- 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 src/core/providers/canvas-schema/canvas-schema.provider.spec.tsx 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 0090999b..45b0c6fd 100644 --- a/src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts +++ b/src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts @@ -82,5 +82,4 @@ export interface CanvasSchemaContextVm { copySelectedTable: () => void; pasteTable: () => void; hasClipboardContent: boolean; - clearClipboard: () => void; } diff --git a/src/core/providers/canvas-schema/canvas-schema.provider.spec.tsx b/src/core/providers/canvas-schema/canvas-schema.provider.spec.tsx new file mode 100644 index 00000000..ed03dd44 --- /dev/null +++ b/src/core/providers/canvas-schema/canvas-schema.provider.spec.tsx @@ -0,0 +1,77 @@ +import { act, renderHook } from '@testing-library/react'; +import { + CanvasSchemaProvider, + useCanvasSchemaContext, +} from './canvas-schema.provider'; +import { + createDefaultDatabaseSchemaVm, + TableVm, +} from './canvas-schema-vlatest.model'; + +const table: TableVm = { + id: 'table-1', + tableName: 'Users', + x: 100, + y: 200, + fields: [{ id: 'field-1', name: '_id', type: 'objectId', PK: true }], +}; + +const renderWithCopiedTable = () => { + const hook = renderHook(() => useCanvasSchemaContext(), { + wrapper: CanvasSchemaProvider, + }); + + act(() => { + hook.result.current.addTable(table); + hook.result.current.doSelectElement(table.id); + }); + act(() => hook.result.current.copySelectedTable()); + + return hook; +}; + +describe('CanvasSchemaProvider New Page clipboard', () => { + it('clears the copied table and prevents pasting into a new page', () => { + const { result } = renderWithCopiedTable(); + expect(result.current.hasClipboardContent).toBe(true); + + act(() => result.current.createEmptySchema()); + + expect(result.current.hasClipboardContent).toBe(false); + expect(result.current.canvasSchema).toEqual( + createDefaultDatabaseSchemaVm() + ); + + act(() => result.current.pasteTable()); + + expect(result.current.canvasSchema).toEqual( + createDefaultDatabaseSchemaVm() + ); + }); + + it('allows copying on the new page with the initial paste offset', () => { + const { result } = renderWithCopiedTable(); + act(() => result.current.pasteTable()); + act(() => result.current.pasteTable()); + act(() => result.current.createEmptySchema()); + + const newTable = { ...table, id: 'table-2', tableName: 'Orders' }; + act(() => { + result.current.addTable(newTable); + result.current.doSelectElement(newTable.id); + }); + act(() => result.current.copySelectedTable()); + act(() => result.current.pasteTable()); + + expect(result.current.hasClipboardContent).toBe(true); + expect(result.current.canvasSchema.tables).toHaveLength(2); + const pastedTable = result.current.canvasSchema.tables[1]; + expect(pastedTable).toMatchObject({ + tableName: 'Orders', + x: newTable.x + 50, + y: newTable.y + 50, + }); + expect(pastedTable.id).not.toBe(newTable.id); + expect(pastedTable.fields[0].id).not.toBe(newTable.fields[0].id); + }); +}); diff --git a/src/core/providers/canvas-schema/canvas-schema.provider.tsx b/src/core/providers/canvas-schema/canvas-schema.provider.tsx index e89d5d29..9ef3be51 100644 --- a/src/core/providers/canvas-schema/canvas-schema.provider.tsx +++ b/src/core/providers/canvas-schema/canvas-schema.provider.tsx @@ -52,6 +52,7 @@ export const CanvasSchemaProvider: React.FC = props => { const createEmptySchema = () => { setSchema(createDefaultDatabaseSchemaVm()); + clearClipboard(); }; const updateFullTable = (table: TableVm) => { @@ -255,7 +256,6 @@ export const CanvasSchemaProvider: React.FC = props => { copySelectedTable, pasteTable, hasClipboardContent: Boolean(clipboardTable), - clearClipboard, }} > {children} diff --git a/src/pods/toolbar/components/new-button/new-button.component.tsx b/src/pods/toolbar/components/new-button/new-button.component.tsx index 5b7ce903..1f9d54a2 100644 --- a/src/pods/toolbar/components/new-button/new-button.component.tsx +++ b/src/pods/toolbar/components/new-button/new-button.component.tsx @@ -8,14 +8,13 @@ import classes from '@/pods/toolbar/toolbar.pod.module.css'; import { SHORTCUTS } from '../../shortcut/shortcut.const'; export const NewButton = () => { - const { createEmptySchema, clearClipboard } = useCanvasSchemaContext(); + const { createEmptySchema } = useCanvasSchemaContext(); const { setFilename, setLoadSample } = useCanvasViewSettingsContext(); const handleNewButtonClick = () => { setFilename(''); createEmptySchema(); setLoadSample(false); - clearClipboard(); }; return (