Skip to content

Commit 1913105

Browse files
authored
Merge branch 'vnext' into fix-workflow
2 parents 2c31757 + e5d831d commit 1913105

31 files changed

Lines changed: 538 additions & 121 deletions

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface TableVm {
66
tableName: string;
77
x: number; // Canvas X Position
88
y: number; // Canvas Y Position
9+
width?: number; // Table width, defaults to DEFAULT_TABLE_WIDTH if not specified
910
}
1011

1112
export interface FieldVm {
@@ -82,4 +83,5 @@ export interface CanvasSchemaContextVm {
8283
copySelectedTable: () => void;
8384
pasteTable: () => void;
8485
hasClipboardContent: boolean;
86+
updateTableWidth: (tableId: GUID, width: number) => void;
8587
}

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,37 @@ export const CanvasSchemaProvider: React.FC<Props> = props => {
6060
);
6161
};
6262

63+
const updateTableWidth = (
64+
tableId: GUID,
65+
width: number,
66+
saveToHistory: boolean = false
67+
) => {
68+
if (saveToHistory) {
69+
// Save to history for undo/redo
70+
setSchema(prevSchema => {
71+
const table = prevSchema.tables.find(t => t.id === tableId);
72+
if (table) {
73+
const updatedTable = { ...table, width };
74+
return updateTable(updatedTable, {
75+
...prevSchema,
76+
isPristine: false,
77+
});
78+
}
79+
return prevSchema;
80+
});
81+
} else {
82+
// Skip history for real-time updates during drag
83+
setSchemaSkipHistory(prevSchema =>
84+
produce(prevSchema, (draft: DatabaseSchemaVm) => {
85+
const table = draft.tables.find((t: TableVm) => t.id === tableId);
86+
if (table) {
87+
table.width = width;
88+
}
89+
})
90+
);
91+
}
92+
};
93+
6394
// TODO: #56 created to track this
6495
// https://github.com/Lemoncode/mongo-modeler/issues/56
6596
const addTable = (table: TableVm) => {
@@ -250,6 +281,7 @@ export const CanvasSchemaProvider: React.FC<Props> = props => {
250281
copySelectedTable,
251282
pasteTable,
252283
hasClipboardContent: Boolean(clipboardTable),
284+
updateTableWidth,
253285
}}
254286
>
255287
{children}

src/core/providers/canvas-schema/canvas.business.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,23 @@ export const moveTableToTop = (
8383
export const calculateRelationXCoordinateOrigin = (
8484
tableOrigin: TableVm,
8585
tableDestination: TableVm
86-
): number =>
87-
tableOrigin.x < tableDestination.x
88-
? tableOrigin.x + TABLE_CONST.DEFAULT_TABLE_WIDTH
86+
): number => {
87+
const tableOriginWidth = tableOrigin.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH;
88+
return tableOrigin.x < tableDestination.x
89+
? tableOrigin.x + tableOriginWidth
8990
: tableOrigin.x;
91+
};
9092

9193
export const calculateRelationXCoordinateEnd = (
9294
tableOrigin: TableVm,
9395
tableDestination: TableVm
94-
): number =>
95-
tableDestination.x <= tableOrigin.x
96-
? tableDestination.x + TABLE_CONST.DEFAULT_TABLE_WIDTH
96+
): number => {
97+
const tableDestinationWidth =
98+
tableDestination.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH;
99+
return tableDestination.x <= tableOrigin.x
100+
? tableDestination.x + tableDestinationWidth
97101
: tableDestination.x;
102+
};
98103

99104
export interface XRelationCoords {
100105
xOrigin: number;

src/core/providers/canvas-schema/canvas.const.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ const LEVEL_INDENTATION = 20; // Indentation per level in nested view
44
const COLLAPSE_ICON_X = 5; // X position of the collapse icon
55
const FIELD_NAME_X_OFFSET = 20; // Initial X offset for the field name
66
const FIELD_TYPE_X = 160; // X position for the field type
7-
const TABLE_WIDTH = 380; // Width of the table rectangle
7+
const DEFAULT_TABLE_WIDTH = 380; // Default width of the table rectangle
88
const HEADER_HEIGHT = FONT_SIZE + ROW_PADDING + 1; // Height of the table header
9-
const DEFAULT_TABLE_WIDTH = TABLE_WIDTH;
109
const ROW_HEIGHT = FONT_SIZE + ROW_PADDING; // Height of the table line
1110
const HORIZONTAL_LEFT_EXTENSION = 20; // Horizontal extension for the relation line 1:1
1211
const HEADER_TITLE_GAP = 15;
@@ -21,9 +20,8 @@ export const TABLE_CONST = {
2120
COLLAPSE_ICON_X,
2221
FIELD_NAME_X_OFFSET,
2322
FIELD_TYPE_X,
24-
TABLE_WIDTH,
25-
HEADER_HEIGHT,
2623
DEFAULT_TABLE_WIDTH,
24+
HEADER_HEIGHT,
2725
ROW_HEIGHT,
2826
HORIZONTAL_LEFT_EXTENSION,
2927
HEADER_TITLE_GAP,

src/pods/canvas/canvas-svg.component.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface Props {
2020
onEditRelation: (relationId: GUID) => void;
2121
onSelectElement: (relationId: GUID | null) => void;
2222
isTabletOrMobileDevice: boolean;
23+
updateTableWidth: (tableId: GUID, width: number) => void;
2324
}
2425

2526
export const CanvasSvgComponent: React.FC<Props> = props => {
@@ -34,6 +35,7 @@ export const CanvasSvgComponent: React.FC<Props> = props => {
3435
onEditRelation,
3536
onSelectElement,
3637
isTabletOrMobileDevice,
38+
updateTableWidth,
3739
} = props;
3840

3941
const clearSelection = () => {
@@ -69,6 +71,7 @@ export const CanvasSvgComponent: React.FC<Props> = props => {
6971
isTabletOrMobileDevice={isTabletOrMobileDevice}
7072
viewBoxSize={viewBoxSize}
7173
zoomFactor={zoomFactor}
74+
updateTableWidth={updateTableWidth}
7275
/>
7376
))}
7477
</svg>

src/pods/canvas/canvas.pod.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const CanvasPod: React.FC = () => {
4545
duplicateSelectedTable,
4646
copySelectedTable,
4747
pasteTable,
48+
updateTableWidth,
4849
} = useCanvasSchemaContext();
4950
const {
5051
canvasViewSettings,
@@ -290,6 +291,7 @@ export const CanvasPod: React.FC = () => {
290291
onEditRelation={handleEditRelation}
291292
onSelectElement={onSelectElement}
292293
isTabletOrMobileDevice={isTabletOrMobileDevice}
294+
updateTableWidth={updateTableWidth}
293295
/>
294296
{!loadSample && (
295297
<CanvasAccessible

src/pods/canvas/components/relation/components/clickeable-self.component.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ interface Props {
88
endCoords: Coords;
99
onClick: (relationId: GUID) => void;
1010
onDoubleClick: (relationId: GUID) => void;
11+
tableWidth: number;
1112
}
1213

1314
export const ClickableSelfComponent: React.FC<Props> = props => {
14-
const { id, startCoords, endCoords, onClick, onDoubleClick } = props;
15+
const { id, startCoords, endCoords, onClick, onDoubleClick, tableWidth } =
16+
props;
1517

1618
const handleClick = (e: React.MouseEvent<SVGLineElement, MouseEvent>) => {
1719
onClick(id);
@@ -22,7 +24,7 @@ export const ClickableSelfComponent: React.FC<Props> = props => {
2224
M ${startCoords.x} ${startCoords.y}
2325
H ${startCoords.x - TABLE_CONST.HORIZONTAL_LEFT_EXTENSION}
2426
V ${endCoords.y}
25-
H ${endCoords.x - TABLE_CONST.TABLE_WIDTH}
27+
H ${endCoords.x - tableWidth}
2628
`;
2729

2830
return (

src/pods/canvas/components/relation/database-relation-collection.business.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { isOverLapping } from './database-relation-collection.business';
55
describe('database-relation-collection.business', () => {
66
describe('isOverLapping function tests', () => {
77
it('non-overlapping tables (before)', () => {
8-
vi.spyOn(TABLE_CONST, 'TABLE_WIDTH', 'get').mockReturnValue(100);
8+
vi.spyOn(TABLE_CONST, 'DEFAULT_TABLE_WIDTH', 'get').mockReturnValue(100);
99
console.log(
1010
`
1111
Table A |====|
@@ -25,7 +25,7 @@ describe('database-relation-collection.business', () => {
2525
});
2626

2727
it('non-overlapping tables (after)', () => {
28-
vi.spyOn(TABLE_CONST, 'TABLE_WIDTH', 'get').mockReturnValue(100);
28+
vi.spyOn(TABLE_CONST, 'DEFAULT_TABLE_WIDTH', 'get').mockReturnValue(100);
2929
console.log(
3030
`
3131
Table A |====|
@@ -45,7 +45,7 @@ describe('database-relation-collection.business', () => {
4545
});
4646

4747
it('overlapping tables (partial)', () => {
48-
vi.spyOn(TABLE_CONST, 'TABLE_WIDTH', 'get').mockReturnValue(100);
48+
vi.spyOn(TABLE_CONST, 'DEFAULT_TABLE_WIDTH', 'get').mockReturnValue(100);
4949
console.log(
5050
`
5151
Table A |====|
@@ -65,7 +65,7 @@ describe('database-relation-collection.business', () => {
6565
});
6666

6767
it('overlapping tables (partial - reverse)', () => {
68-
vi.spyOn(TABLE_CONST, 'TABLE_WIDTH', 'get').mockReturnValue(100);
68+
vi.spyOn(TABLE_CONST, 'DEFAULT_TABLE_WIDTH', 'get').mockReturnValue(100);
6969
console.log(
7070
`
7171
Table A |====|
@@ -85,7 +85,7 @@ describe('database-relation-collection.business', () => {
8585
});
8686

8787
it('overlapping tables (full)', () => {
88-
vi.spyOn(TABLE_CONST, 'TABLE_WIDTH', 'get').mockReturnValue(100);
88+
vi.spyOn(TABLE_CONST, 'DEFAULT_TABLE_WIDTH', 'get').mockReturnValue(100);
8989
console.log(
9090
`
9191
Table A |====|
@@ -105,7 +105,7 @@ describe('database-relation-collection.business', () => {
105105
});
106106

107107
it('overlapping tables (edge)', () => {
108-
vi.spyOn(TABLE_CONST, 'TABLE_WIDTH', 'get').mockReturnValue(100);
108+
vi.spyOn(TABLE_CONST, 'DEFAULT_TABLE_WIDTH', 'get').mockReturnValue(100);
109109
console.log(
110110
`
111111
Table A |====|
@@ -125,7 +125,7 @@ describe('database-relation-collection.business', () => {
125125
});
126126

127127
it('overlapping tables (edge - reverse)', () => {
128-
vi.spyOn(TABLE_CONST, 'TABLE_WIDTH', 'get').mockReturnValue(100);
128+
vi.spyOn(TABLE_CONST, 'DEFAULT_TABLE_WIDTH', 'get').mockReturnValue(100);
129129
console.log(
130130
`
131131
Table A |====|
Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
1-
import { TABLE_CONST } from '@/core/providers';
1+
import { TABLE_CONST, TableVm } from '@/core/providers';
22

3-
export const isOverLapping = (
3+
// Overloaded function for backward compatibility with tests
4+
export function isOverLapping(
45
fromTableXCoord: number,
56
toTableXCoord: number
6-
): boolean =>
7-
fromTableXCoord + TABLE_CONST.TABLE_WIDTH > toTableXCoord &&
8-
fromTableXCoord < toTableXCoord + TABLE_CONST.TABLE_WIDTH;
7+
): boolean;
8+
export function isOverLapping(fromTable: TableVm, toTable: TableVm): boolean;
9+
export function isOverLapping(
10+
fromTableOrX: TableVm | number,
11+
toTableOrX: TableVm | number
12+
): boolean {
13+
if (typeof fromTableOrX === 'number' && typeof toTableOrX === 'number') {
14+
// Legacy behavior for tests - use default width
15+
return (
16+
fromTableOrX + TABLE_CONST.DEFAULT_TABLE_WIDTH > toTableOrX &&
17+
fromTableOrX < toTableOrX + TABLE_CONST.DEFAULT_TABLE_WIDTH
18+
);
19+
} else {
20+
// New behavior - use actual table widths
21+
const fromTable = fromTableOrX as TableVm;
22+
const toTable = toTableOrX as TableVm;
23+
const fromTableWidth = fromTable.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH;
24+
const toTableWidth = toTable.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH;
25+
26+
return (
27+
fromTable.x + fromTableWidth > toTable.x &&
28+
fromTable.x < toTable.x + toTableWidth
29+
);
30+
}
31+
}

src/pods/canvas/components/relation/database-relation-collection.component.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import React from 'react';
22
import { Coords, GUID } from '@/core/model';
3-
import { DatabaseSchemaVm, RelationVm } from '@/core/providers/canvas-schema';
3+
import {
4+
DatabaseSchemaVm,
5+
RelationVm,
6+
TABLE_CONST,
7+
} from '@/core/providers/canvas-schema';
48
import {
59
calculateRelationXCoordinate,
610
calculateRelationYCoordinate,
@@ -52,7 +56,7 @@ export const DatabaseRelationCollectionComponent: React.FC<
5256

5357
const getLayoutType = (): LayoutType => {
5458
if (relation.fromTableId === relation.toTableId) return 'self';
55-
if (isOverLapping(fromTable.x, toTable.x)) return 'overlapping';
59+
if (isOverLapping(fromTable, toTable)) return 'overlapping';
5660
return 'straight';
5761
};
5862

@@ -70,6 +74,7 @@ export const DatabaseRelationCollectionComponent: React.FC<
7074
startCoords={startCoords}
7175
endCoords={endCoords}
7276
isSelected={relation.id === schema.selectedElementId}
77+
tableWidth={fromTable.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH}
7378
/>
7479
);
7580
case 'overlapping':
@@ -82,6 +87,10 @@ export const DatabaseRelationCollectionComponent: React.FC<
8287
startCoords={startCoords}
8388
endCoords={endCoords}
8489
isSelected={relation.id === schema.selectedElementId}
90+
startTableWidth={
91+
fromTable.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH
92+
}
93+
endTableWidth={toTable.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH}
8594
/>
8695
);
8796
case 'straight':
@@ -94,6 +103,10 @@ export const DatabaseRelationCollectionComponent: React.FC<
94103
startCoords={startCoords}
95104
endCoords={endCoords}
96105
isSelected={relation.id === schema.selectedElementId}
106+
startTableWidth={
107+
fromTable.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH
108+
}
109+
endTableWidth={toTable.width ?? TABLE_CONST.DEFAULT_TABLE_WIDTH}
97110
/>
98111
);
99112
}

0 commit comments

Comments
 (0)