Skip to content

Commit 21dfae4

Browse files
authored
Merge pull request #538 from Lemoncode/vnext
copy paste functionallity
2 parents afcdb7e + c4bd05e commit 21dfae4

20 files changed

Lines changed: 277 additions & 7 deletions

.github/workflows/ci.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,27 @@ jobs:
2222
run: npm run tsc-check
2323
- name: Tests front
2424
run: npm test
25+
26+
e2e-tests:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- name: Checkout repository
30+
uses: actions/checkout@v2
31+
32+
- name: Use Node.js 18.13.0
33+
uses: actions/setup-node@v2
34+
with:
35+
node-version: '18.13.0'
36+
cache: 'npm'
37+
38+
- name: Install dependencies
39+
run: npm ci
40+
41+
- name: Build
42+
run: npm run build
43+
44+
- name: Check TypeScript Types
45+
run: npm run tsc-check
46+
47+
- name: Run E2E tests
48+
run: npm run ci:e2e

e2e/add-new-collection.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('opens MongoDB Designer, adds collection, and checks "New Collection" visibility', async ({
4+
page,
5+
}) => {
6+
await page.goto('');
7+
8+
await page.getByRole('link', { name: 'Launch MongoDB Designer' }).click();
9+
await expect(page).toHaveURL('http://localhost:5173/editor.html');
10+
11+
const newButton = page.getByRole('button', { name: 'New' });
12+
await expect(newButton).toBeVisible();
13+
await newButton.click();
14+
15+
const addCollectionButton = page
16+
.getByRole('button', { name: 'Add Collection' })
17+
.first();
18+
await expect(addCollectionButton).toBeVisible();
19+
await addCollectionButton.click();
20+
21+
const applyButton = page.getByRole('button', { name: 'Apply' });
22+
await expect(applyButton).toBeVisible();
23+
await expect(applyButton).toBeEnabled();
24+
await applyButton.click();
25+
26+
const newCollectionText = page.locator('svg g text', {
27+
hasText: 'New Collection',
28+
});
29+
await expect(newCollectionText).toBeVisible();
30+
});

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"test": "vitest",
1515
"prepare": "husky || \"No need to install husky\"",
1616
"tsc-check": "tsc --noEmit",
17-
"e2e": "playwright test --ui"
17+
"e2e": "playwright test --ui",
18+
"ci:e2e": "playwright test"
1819
},
1920
"dependencies": {
2021
"@lemoncode/fonk": "^1.5.4",

playwright.config.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,6 @@ export default defineConfig({
2626
use: { ...devices['Desktop Firefox'] },
2727
},
2828

29-
{
30-
name: 'webkit',
31-
use: { ...devices['Desktop Safari'] },
32-
},
33-
3429
/* Test against mobile viewports. */
3530
// {
3631
// name: 'Mobile Chrome',
@@ -54,6 +49,7 @@ export default defineConfig({
5449
/* Run your local dev server before starting the tests */
5550
webServer: {
5651
command: 'npm run dev',
52+
url: BASE_URL,
5753
reuseExistingServer: !process.env.CI,
5854
},
5955
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export const CopyIcon = () => {
2+
return (
3+
<svg
4+
xmlns="http://www.w3.org/2000/svg"
5+
width="1.2em"
6+
height="1.2em"
7+
viewBox="0 0 256 256"
8+
>
9+
<path
10+
fill="currentColor"
11+
d="M216 32H88a8 8 0 0 0-8 8v40H40a8 8 0 0 0-8 8v128a8 8 0 0 0 8 8h128a8 8 0 0 0 8-8v-40h40a8 8 0 0 0 8-8V40a8 8 0 0 0-8-8m-56 176H48V96h112Zm48-48h-32V88a8 8 0 0 0-8-8H96V48h112Z"
12+
/>
13+
</svg>
14+
);
15+
};

src/common/components/icons/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ export * from './add-folder.component';
2222
export * from './down-icon';
2323
export * from './up-icon.component';
2424
export * from './remove-icon.component';
25+
export * from './copy-icon.component';
26+
export * from './paste-icon.component';
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export const PasteIcon = () => {
2+
return (
3+
<svg
4+
xmlns="http://www.w3.org/2000/svg"
5+
width="1.2em"
6+
height="1.2em"
7+
viewBox="0 0 256 256"
8+
>
9+
<path
10+
fill="currentColor"
11+
d="M200 32h-36.26a47.92 47.92 0 0 0-71.48 0H56a16 16 0 0 0-16 16v168a16 16 0 0 0 16 16h144a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16m-72 0a32 32 0 0 1 32 32H96a32 32 0 0 1 32-32m72 184H56V48h26.75A47.9 47.9 0 0 0 80 64v8a8 8 0 0 0 8 8h80a8 8 0 0 0 8-8v-8a47.9 47.9 0 0 0-2.75-16H200Z"
12+
/>
13+
</svg>
14+
);
15+
};

src/core/providers/canvas-schema/canvas-schema-vlatest.model.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,8 @@ export interface CanvasSchemaContextVm {
7878
updateFullRelation: (relation: RelationVm) => void;
7979
deleteSelectedItem: (selectedElementId: GUID) => void;
8080
switchIsPristine: (isPristine: boolean) => void;
81+
duplicateSelectedTable: () => void;
82+
copySelectedTable: () => void;
83+
pasteTable: () => void;
84+
hasClipboardContent: boolean;
8185
}

src/core/providers/canvas-schema/canvas-schema.provider.tsx

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { produce } from 'immer';
33
import { CanvasSchemaContext } from './canvas-schema.context';
44
import {
@@ -157,6 +157,75 @@ export const CanvasSchemaProvider: React.FC<Props> = props => {
157157
}));
158158
};
159159

160+
const duplicateSelectedTable = () => {
161+
setSchema(prevSchema => {
162+
if (!prevSchema.selectedElementId) return prevSchema;
163+
164+
const selectedTable = prevSchema.tables.find(
165+
table => table.id === prevSchema.selectedElementId
166+
);
167+
168+
if (!selectedTable) return prevSchema;
169+
170+
// Create duplicate with new IDs
171+
const duplicateTable: TableVm = {
172+
...selectedTable,
173+
id: crypto.randomUUID(), // Generate new ID
174+
x: selectedTable.x + 50, // Offset position
175+
y: selectedTable.y + 50,
176+
fields: selectedTable.fields.map(field => ({
177+
...field,
178+
id: crypto.randomUUID(), // New IDs for fields
179+
})),
180+
};
181+
182+
return {
183+
...prevSchema,
184+
tables: [...prevSchema.tables, duplicateTable],
185+
isPristine: false,
186+
};
187+
});
188+
};
189+
190+
const [clipboardTable, setClipboardTable] = useState<TableVm | null>(null);
191+
const [pasteOffset, setPasteOffset] = useState({ x: 0, y: 0 });
192+
193+
const copySelectedTable = () => {
194+
const selectedTable = canvasSchema.tables.find(
195+
table => table.id === canvasSchema.selectedElementId
196+
);
197+
if (selectedTable) {
198+
setClipboardTable(selectedTable);
199+
setPasteOffset({ x: 0, y: 0 }); // Reset offset on copy
200+
}
201+
};
202+
203+
const pasteTable = () => {
204+
if (clipboardTable) {
205+
// Increment offset
206+
const newOffset = { x: pasteOffset.x + 50, y: pasteOffset.y + 50 };
207+
208+
const newTable: TableVm = {
209+
...clipboardTable,
210+
id: crypto.randomUUID(),
211+
x: clipboardTable.x + newOffset.x,
212+
y: clipboardTable.y + newOffset.y,
213+
fields: clipboardTable.fields.map(field => ({
214+
...field,
215+
id: crypto.randomUUID(),
216+
})),
217+
};
218+
219+
setSchema(prev => ({
220+
...prev,
221+
tables: [...prev.tables, newTable],
222+
isPristine: false,
223+
}));
224+
225+
setPasteOffset(newOffset);
226+
}
227+
};
228+
160229
return (
161230
<CanvasSchemaContext.Provider
162231
value={{
@@ -177,6 +246,10 @@ export const CanvasSchemaProvider: React.FC<Props> = props => {
177246
updateFullRelation,
178247
deleteSelectedItem,
179248
switchIsPristine: switchIsPristine,
249+
duplicateSelectedTable,
250+
copySelectedTable,
251+
pasteTable,
252+
hasClipboardContent: Boolean(clipboardTable),
180253
}}
181254
>
182255
{children}

0 commit comments

Comments
 (0)