mirror of
https://github.com/chartdb/chartdb.git
synced 2025-11-02 13:03:17 +00:00
fix(expanded-table): persist expanded state across renders (#707)
* fix(expanded-table): persist expanded state across renders * fix(reorder-tables): account for table sizes when reordering * some fixes --------- Co-authored-by: Guy Ben-Aharon <baguy3@gmail.com>
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
||||
import { DatabaseType } from './database-type';
|
||||
import type { DatabaseMetadata } from '../data/import-metadata/metadata-types/database-metadata';
|
||||
import { z } from 'zod';
|
||||
import { getTableDimensions } from '@/pages/editor-page/canvas/canvas-utils';
|
||||
|
||||
export interface DBTable {
|
||||
id: string;
|
||||
@@ -41,6 +42,7 @@ export interface DBTable {
|
||||
width?: number;
|
||||
comments?: string;
|
||||
order?: number;
|
||||
expanded?: boolean;
|
||||
}
|
||||
|
||||
export const dbTableSchema: z.ZodType<DBTable> = z.object({
|
||||
@@ -58,6 +60,7 @@ export const dbTableSchema: z.ZodType<DBTable> = z.object({
|
||||
width: z.number().optional(),
|
||||
comments: z.string().optional(),
|
||||
order: z.number().optional(),
|
||||
expanded: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export const shouldShowTablesBySchemaFilter = (
|
||||
@@ -175,8 +178,8 @@ export const adjustTablePositions = ({
|
||||
const relationships = deepCopy(inputRelationships);
|
||||
|
||||
const adjustPositionsForTables = (tablesToAdjust: DBTable[]) => {
|
||||
const tableWidth = 200;
|
||||
const tableHeight = 300;
|
||||
const defaultTableWidth = 200;
|
||||
const defaultTableHeight = 300;
|
||||
const gapX = 100;
|
||||
const gapY = 100;
|
||||
const startX = 100;
|
||||
@@ -205,6 +208,20 @@ export const adjustTablePositions = ({
|
||||
const positionedTables = new Set<string>();
|
||||
const tablePositions = new Map<string, { x: number; y: number }>();
|
||||
|
||||
const getTableWidthAndHeight = (
|
||||
tableId: string
|
||||
): {
|
||||
width: number;
|
||||
height: number;
|
||||
} => {
|
||||
const table = tablesToAdjust.find((t) => t.id === tableId);
|
||||
|
||||
if (!table)
|
||||
return { width: defaultTableWidth, height: defaultTableHeight };
|
||||
|
||||
return getTableDimensions(table);
|
||||
};
|
||||
|
||||
const isOverlapping = (
|
||||
x: number,
|
||||
y: number,
|
||||
@@ -212,9 +229,11 @@ export const adjustTablePositions = ({
|
||||
): boolean => {
|
||||
for (const [tableId, pos] of tablePositions) {
|
||||
if (tableId === currentTableId) continue;
|
||||
|
||||
const { width, height } = getTableWidthAndHeight(tableId);
|
||||
if (
|
||||
Math.abs(x - pos.x) < tableWidth + gapX &&
|
||||
Math.abs(y - pos.y) < tableHeight + gapY
|
||||
Math.abs(x - pos.x) < width + gapX &&
|
||||
Math.abs(y - pos.y) < height + gapY
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -227,7 +246,8 @@ export const adjustTablePositions = ({
|
||||
baseY: number,
|
||||
tableId: string
|
||||
): { x: number; y: number } => {
|
||||
const spiralStep = Math.max(tableWidth, tableHeight) / 2;
|
||||
const { width, height } = getTableWidthAndHeight(tableId);
|
||||
const spiralStep = Math.max(width, height) / 2;
|
||||
let angle = 0;
|
||||
let radius = 0;
|
||||
let iterations = 0;
|
||||
@@ -279,10 +299,21 @@ export const adjustTablePositions = ({
|
||||
(t) => t.id === connectedTableId
|
||||
);
|
||||
if (connectedTable) {
|
||||
const { width: tableWidth, height: tableHeight } =
|
||||
getTableWidthAndHeight(table.id);
|
||||
const {
|
||||
width: connectedTableWidth,
|
||||
height: connectedTableHeight,
|
||||
} = getTableWidthAndHeight(connectedTableId);
|
||||
const avgWidth = (tableWidth + connectedTableWidth) / 2;
|
||||
|
||||
const avgHeight =
|
||||
(tableHeight + connectedTableHeight) / 2;
|
||||
|
||||
const newX =
|
||||
x + Math.cos(angle) * (tableWidth + gapX * 2);
|
||||
x + Math.cos(angle) * (avgWidth + gapX * 2);
|
||||
const newY =
|
||||
y + Math.sin(angle) * (tableHeight + gapY * 2);
|
||||
y + Math.sin(angle) * (avgHeight + gapY * 2);
|
||||
positionTable(connectedTable, newX, newY);
|
||||
angle += angleStep;
|
||||
}
|
||||
@@ -295,6 +326,9 @@ export const adjustTablePositions = ({
|
||||
if (!positionedTables.has(table.id)) {
|
||||
const row = Math.floor(index / 6);
|
||||
const col = index % 6;
|
||||
const { width: tableWidth, height: tableHeight } =
|
||||
getTableWidthAndHeight(table.id);
|
||||
|
||||
const x = startX + col * (tableWidth + gapX * 2);
|
||||
const y = startY + row * (tableHeight + gapY * 2);
|
||||
positionTable(table, x, y);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import type { Cardinality } from '@/lib/domain/db-relationship';
|
||||
import { MIN_TABLE_SIZE, type TableNodeType } from './table-node/table-node';
|
||||
import {
|
||||
MIN_TABLE_SIZE,
|
||||
TABLE_MINIMIZED_FIELDS,
|
||||
type TableNodeType,
|
||||
} from './table-node/table-node';
|
||||
import { addEdge, createGraph, removeEdge, type Graph } from '@/lib/graph';
|
||||
import type { DBTable } from '@/lib/domain/db-table';
|
||||
|
||||
@@ -27,9 +31,8 @@ const calcRect = ({
|
||||
table?.width ??
|
||||
MIN_TABLE_SIZE;
|
||||
const height = node
|
||||
? (node?.measured?.height ??
|
||||
calcTableHeight(node?.data.table.fields.length ?? 0))
|
||||
: calcTableHeight(table?.fields.length ?? 0);
|
||||
? (node?.measured?.height ?? calcTableHeight(node.data.table))
|
||||
: calcTableHeight(table);
|
||||
|
||||
return {
|
||||
id,
|
||||
@@ -108,17 +111,35 @@ export const findOverlappingTables = ({
|
||||
return graph;
|
||||
};
|
||||
|
||||
export const calcTableHeight = (fieldCount: number): number => {
|
||||
const fieldHeight = 32; // h-8 per field
|
||||
export const calcTableHeight = (table?: DBTable): number => {
|
||||
if (!table) {
|
||||
return 300;
|
||||
}
|
||||
|
||||
return Math.min(fieldCount, 11) * fieldHeight + 48;
|
||||
const FIELD_HEIGHT = 32; // h-8 per field
|
||||
const TABLE_FOOTER_HEIGHT = 32; // h-8 for show more button
|
||||
const TABLE_HEADER_HEIGHT = 42;
|
||||
// Calculate how many fields are visible
|
||||
const fieldCount = table.fields.length;
|
||||
let visibleFieldCount = fieldCount;
|
||||
|
||||
// If not expanded, use minimum of field count and TABLE_MINIMIZED_FIELDS
|
||||
if (!table.expanded) {
|
||||
visibleFieldCount = Math.min(fieldCount, TABLE_MINIMIZED_FIELDS);
|
||||
}
|
||||
|
||||
// Calculate height based on visible fields
|
||||
const fieldsHeight = visibleFieldCount * FIELD_HEIGHT;
|
||||
const showMoreButtonHeight =
|
||||
fieldCount > TABLE_MINIMIZED_FIELDS ? TABLE_FOOTER_HEIGHT : 0;
|
||||
|
||||
return TABLE_HEADER_HEIGHT + fieldsHeight + showMoreButtonHeight;
|
||||
};
|
||||
|
||||
export const getTableDimensions = (
|
||||
table: DBTable
|
||||
): { width: number; height: number } => {
|
||||
const fieldCount = table.fields.length;
|
||||
const height = calcTableHeight(fieldCount);
|
||||
const height = calcTableHeight(table);
|
||||
const width = table.width || MIN_TABLE_SIZE;
|
||||
return { width, height };
|
||||
};
|
||||
|
||||
@@ -760,7 +760,10 @@ export const Canvas: React.FC<CanvasProps> = ({ initialTables }) => {
|
||||
|
||||
const measured = {
|
||||
...(node.measured ?? {}),
|
||||
height: calcTableHeight(event.data.fields.length),
|
||||
height: calcTableHeight({
|
||||
...node.data.table,
|
||||
fields: event.data.fields,
|
||||
}),
|
||||
};
|
||||
|
||||
newOverlappingGraph = findTableOverlapping(
|
||||
|
||||
@@ -60,7 +60,7 @@ export const TableNode: React.FC<NodeProps<TableNodeType>> = React.memo(
|
||||
const { updateTable, relationships, readonly } = useChartDB();
|
||||
const edges = useStore((store) => store.edges) as EdgeType[];
|
||||
const { openTableFromSidebar, selectSidebarSection } = useLayout();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [expanded, setExpanded] = useState(table.expanded ?? false);
|
||||
const { t } = useTranslation();
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [tableName, setTableName] = useState(table.name);
|
||||
@@ -138,9 +138,13 @@ export const TableNode: React.FC<NodeProps<TableNodeType>> = React.memo(
|
||||
});
|
||||
}, [table.id, updateTable]);
|
||||
|
||||
const toggleExpand = () => {
|
||||
setExpanded(!expanded);
|
||||
};
|
||||
const toggleExpand = useCallback(() => {
|
||||
setExpanded((prev) => {
|
||||
const value = !prev;
|
||||
updateTable(table.id, { expanded: value });
|
||||
return value;
|
||||
});
|
||||
}, [table.id, updateTable]);
|
||||
|
||||
const isMustDisplayedField = useCallback(
|
||||
(field: DBField) => {
|
||||
|
||||
Reference in New Issue
Block a user