From c725c098298eac3c351878fd2dac62eb4edc65a9 Mon Sep 17 00:00:00 2001 From: junkisai Date: Wed, 11 Dec 2024 16:41:53 +0900 Subject: [PATCH 1/5] feat: use org.eclipse.elk.layered in elk.algorithm --- .../ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts index 317b49853..17e181959 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts @@ -7,9 +7,7 @@ import { convertNodesToElkNodes } from './convertNodesToElkNodes' const elk = new ELK() const layoutOptions: LayoutOptions = { - 'elk.aspectRatio': '1.78', // 16:0 - 'elk.algorithm': 'org.eclipse.elk.force', - 'elk.force.model': 'EADES', + 'elk.algorithm': 'org.eclipse.elk.layered', } type Params = { From 8ac6a9bd7e36676e6b356a01347dba6cabbe1b2f Mon Sep 17 00:00:00 2001 From: junkisai Date: Thu, 12 Dec 2024 11:48:31 +0900 Subject: [PATCH 2/5] feat: implement show mode management with user editing store --- .../Toolbar/ShowModeMenu/ShowModeMenu.tsx | 13 ++++++------- .../packages/erd-core/src/schemas/showMode/index.ts | 2 ++ .../erd-core/src/schemas/showMode/schemas.ts | 3 +++ .../packages/erd-core/src/schemas/showMode/types.ts | 4 ++++ .../erd-core/src/stores/userEditing/actions.ts | 5 +++++ .../erd-core/src/stores/userEditing/store.ts | 3 +++ 6 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 frontend/packages/erd-core/src/schemas/showMode/index.ts create mode 100644 frontend/packages/erd-core/src/schemas/showMode/schemas.ts create mode 100644 frontend/packages/erd-core/src/schemas/showMode/types.ts diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/Toolbar/ShowModeMenu/ShowModeMenu.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/Toolbar/ShowModeMenu/ShowModeMenu.tsx index f58ec0128..1288bffdf 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/Toolbar/ShowModeMenu/ShowModeMenu.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/Toolbar/ShowModeMenu/ShowModeMenu.tsx @@ -1,3 +1,5 @@ +import { type ShowMode, showModeSchema } from '@/schemas/showMode' +import { updateShowMode, useUserEditingStore } from '@/stores' import { Button, ChevronDown, @@ -8,13 +10,10 @@ import { DropdownMenuRoot, DropdownMenuTrigger, } from '@liam-hq/ui' -import { type FC, useCallback, useState } from 'react' -import { type InferOutput, picklist, safeParse } from 'valibot' +import { type FC, useCallback } from 'react' +import { safeParse } from 'valibot' import styles from './ShowModeMenu.module.css' -const showModeSchema = picklist(['ALL_FIELDS', 'TABLE_NAME', 'KEY_ONLY']) -type ShowMode = InferOutput - const OPTION_LIST: { value: ShowMode; label: string }[] = [ { value: 'ALL_FIELDS', label: 'All Fields' }, { value: 'TABLE_NAME', label: 'Table Name' }, @@ -22,13 +21,13 @@ const OPTION_LIST: { value: ShowMode; label: string }[] = [ ] export const ShowModeMenu: FC = () => { - const [showMode, setShowMode] = useState('ALL_FIELDS') + const { showMode } = useUserEditingStore() const handleChangeValue = useCallback((value: string) => { const parsed = safeParse(showModeSchema, value) if (parsed.success) { - setShowMode(parsed.output) + updateShowMode(parsed.output) } }, []) diff --git a/frontend/packages/erd-core/src/schemas/showMode/index.ts b/frontend/packages/erd-core/src/schemas/showMode/index.ts new file mode 100644 index 000000000..68de05596 --- /dev/null +++ b/frontend/packages/erd-core/src/schemas/showMode/index.ts @@ -0,0 +1,2 @@ +export * from './schemas' +export * from './types' diff --git a/frontend/packages/erd-core/src/schemas/showMode/schemas.ts b/frontend/packages/erd-core/src/schemas/showMode/schemas.ts new file mode 100644 index 000000000..7fb42217b --- /dev/null +++ b/frontend/packages/erd-core/src/schemas/showMode/schemas.ts @@ -0,0 +1,3 @@ +import { picklist } from 'valibot' + +export const showModeSchema = picklist(['ALL_FIELDS', 'TABLE_NAME', 'KEY_ONLY']) diff --git a/frontend/packages/erd-core/src/schemas/showMode/types.ts b/frontend/packages/erd-core/src/schemas/showMode/types.ts new file mode 100644 index 000000000..0bda143f9 --- /dev/null +++ b/frontend/packages/erd-core/src/schemas/showMode/types.ts @@ -0,0 +1,4 @@ +import type { InferOutput } from 'valibot' +import type { showModeSchema } from './schemas' + +export type ShowMode = InferOutput diff --git a/frontend/packages/erd-core/src/stores/userEditing/actions.ts b/frontend/packages/erd-core/src/stores/userEditing/actions.ts index a7bc60c7d..628671ff8 100644 --- a/frontend/packages/erd-core/src/stores/userEditing/actions.ts +++ b/frontend/packages/erd-core/src/stores/userEditing/actions.ts @@ -1,5 +1,10 @@ +import type { ShowMode } from '@/schemas/showMode' import { userEditingStore } from './store' export const updateActiveTableName = (tableName: string | undefined) => { userEditingStore.active.tableName = tableName } + +export const updateShowMode = (showMode: ShowMode) => { + userEditingStore.showMode = showMode +} diff --git a/frontend/packages/erd-core/src/stores/userEditing/store.ts b/frontend/packages/erd-core/src/stores/userEditing/store.ts index ceee145a7..8c899bf67 100644 --- a/frontend/packages/erd-core/src/stores/userEditing/store.ts +++ b/frontend/packages/erd-core/src/stores/userEditing/store.ts @@ -1,13 +1,16 @@ +import type { ShowMode } from '@/schemas/showMode' import { proxy } from 'valtio' type UserEditingStore = { active: { tableName: string | undefined } + showMode: ShowMode } export const userEditingStore = proxy({ active: { tableName: undefined, }, + showMode: 'ALL_FIELDS', }) From a3b0c917e71bdae50603897e277782e23bba8e5e Mon Sep 17 00:00:00 2001 From: junkisai Date: Thu, 12 Dec 2024 12:09:33 +0900 Subject: [PATCH 3/5] feat: enhance convertDBStructureToNodes to support show mode --- .../RelatedTables/RelatedTables.tsx | 5 +- .../components/ERDRenderer/ERDRenderer.tsx | 8 +- .../ERDRenderer/convertDBStructureToNodes.ts | 94 +++++-------------- 3 files changed, 33 insertions(+), 74 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableDetail/RelatedTables/RelatedTables.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableDetail/RelatedTables/RelatedTables.tsx index 960e66caf..b8d6ab1d7 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableDetail/RelatedTables/RelatedTables.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableDetail/RelatedTables/RelatedTables.tsx @@ -15,7 +15,10 @@ type Props = { export const RelatedTables: FC = ({ table }) => { const dbStructure = useDBStructureStore() const extractedDBStructure = extractDBStructureForTable(table, dbStructure) - const { nodes, edges } = convertDBStructureToNodes(extractedDBStructure) + const { nodes, edges } = convertDBStructureToNodes({ + dbStructure: extractedDBStructure, + showMode: 'TABLE_NAME', + }) return (
diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDRenderer.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDRenderer.tsx index 9ffadd900..eca75c086 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDRenderer.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDRenderer.tsx @@ -11,14 +11,18 @@ import { ERDContent } from './ERDContent' import styles from './ERDRenderer.module.css' import { LeftPane } from './LeftPane' import '@/styles/globals.css' -import { useDBStructureStore } from '@/stores' +import { useDBStructureStore, useUserEditingStore } from '@/stores' import { TableDetailDrawer, TableDetailDrawerRoot } from './TableDetailDrawer' import { convertDBStructureToNodes } from './convertDBStructureToNodes' export const ERDRenderer: FC = () => { const defaultOpen = getSidebarStateFromCookie() + const { showMode } = useUserEditingStore() const dbStructure = useDBStructureStore() - const { nodes, edges } = convertDBStructureToNodes(dbStructure) + const { nodes, edges } = convertDBStructureToNodes({ + dbStructure, + showMode, + }) return (
diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/convertDBStructureToNodes.ts b/frontend/packages/erd-core/src/components/ERDRenderer/convertDBStructureToNodes.ts index 521b8f084..d4841383d 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/convertDBStructureToNodes.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/convertDBStructureToNodes.ts @@ -1,76 +1,23 @@ -import type { DBStructure, Table } from '@liam-hq/db-structure' +import type { ShowMode } from '@/schemas/showMode' +import type { DBStructure } from '@liam-hq/db-structure' import type { Edge, Node } from '@xyflow/react' -type Data = { - table: Table +type Params = { + dbStructure: DBStructure + showMode: ShowMode } -type TableNodeType = Node - -const getCategory = ( - score: { primary: number; foreign: number } | undefined, -): number => { - if (!score) return 4 - if (score.foreign === 0 && score.primary > 0) return 1 - if (score.primary > 0) return 2 - if (score.foreign > 0) return 3 - return 4 -} - -const sortNodes = ( - nodes: TableNodeType[], - dbStructure: DBStructure, -): TableNodeType[] => { - const relationships = Object.values(dbStructure.relationships) - const tableScore: Record = {} - - for (const node of nodes) { - tableScore[node.data.table.name] = { primary: 0, foreign: 0 } - } - - for (const { primaryTableName, foreignTableName } of relationships) { - if (tableScore[primaryTableName]) { - tableScore[primaryTableName].primary++ - } - if (tableScore[foreignTableName]) { - tableScore[foreignTableName].foreign++ - } - } - - return nodes.sort((a, b) => { - const scoreA = tableScore[a.data.table.name] - const scoreB = tableScore[b.data.table.name] - - const categoryA = getCategory(scoreA) - const categoryB = getCategory(scoreB) - - if (categoryA !== categoryB) { - return categoryA - categoryB - } - - const primaryA = scoreA?.primary ?? 0 - const primaryB = scoreB?.primary ?? 0 - if (primaryA !== primaryB) { - return primaryB - primaryA - } - - const foreignA = scoreA?.foreign ?? 0 - const foreignB = scoreB?.foreign ?? 0 - if (foreignA !== foreignB) { - return foreignA - foreignB - } - - return a.data.table.name.localeCompare(b.data.table.name) - }) -} - -export const convertDBStructureToNodes = ( - dbStructure: DBStructure, -): { nodes: Node[]; edges: Edge[] } => { +export const convertDBStructureToNodes = ({ + dbStructure, + showMode, +}: Params): { + nodes: Node[] + edges: Edge[] +} => { const tables = Object.values(dbStructure.tables) const relationships = Object.values(dbStructure.relationships) - const nodes: TableNodeType[] = tables.map((table) => { + const nodes: Node[] = tables.map((table) => { return { id: table.name, type: 'table', @@ -83,20 +30,25 @@ export const convertDBStructureToNodes = ( }, } }) - const sortedNodes = sortNodes(nodes, dbStructure) - const edges = relationships.map((rel) => ({ + const edges: Edge[] = relationships.map((rel) => ({ id: rel.name, type: 'relationship', source: rel.primaryTableName, target: rel.foreignTableName, - sourceHandle: `${rel.primaryTableName}-${rel.primaryColumnName}`, - targetHandle: `${rel.foreignTableName}-${rel.foreignColumnName}`, + sourceHandle: + showMode === 'TABLE_NAME' + ? null + : `${rel.primaryTableName}-${rel.primaryColumnName}`, + targetHandle: + showMode === 'TABLE_NAME' + ? null + : `${rel.foreignTableName}-${rel.foreignColumnName}`, data: { relationship: rel }, style: { opacity: 0, }, })) - return { nodes: sortedNodes, edges } + return { nodes, edges } } From 0399ad15842b23b6f731754192e1b2d9b06605c0 Mon Sep 17 00:00:00 2001 From: junkisai Date: Thu, 12 Dec 2024 12:09:46 +0900 Subject: [PATCH 4/5] feat: add show mode support for TableHeader and TableNode components --- .../TableNode/TableHeader/TableHeader.tsx | 22 +++ .../ERDContent/TableNode/TableNode.tsx | 128 +++++++++--------- 2 files changed, 88 insertions(+), 62 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableHeader/TableHeader.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableHeader/TableHeader.tsx index 51e488fe0..56e50c247 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableHeader/TableHeader.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableHeader/TableHeader.tsx @@ -1,4 +1,6 @@ +import { useDBStructureStore, useUserEditingStore } from '@/stores' import { Table2 } from '@liam-hq/ui' +import { Handle, Position } from '@xyflow/react' import type { FC } from 'react' import styles from './TableHeader.module.css' @@ -7,10 +9,30 @@ type Props = { } export const TableHeader: FC = ({ name }) => { + const { showMode } = useUserEditingStore() + const { relationships } = useDBStructureStore() + + const isTarget = Object.values(relationships).some( + (relationship) => relationship.foreignTableName === name, + ) + const isSource = Object.values(relationships).some( + (relationship) => relationship.primaryTableName === name, + ) + return (
{name} + {showMode === 'TABLE_NAME' && ( + <> + {isTarget && ( + + )} + {isSource && ( + + )} + + )}
) } diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableNode.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableNode.tsx index 561421eb2..ecc5a3be0 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableNode.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableNode.tsx @@ -25,6 +25,8 @@ export const TableNode: FC = ({ data: { table } }) => { active: { tableName }, } = useUserEditingStore() const isActive = tableName === table.name + const { showMode } = useUserEditingStore() + const handleClick = useCallback(() => { updateActiveTableName(table.name) }, [table]) @@ -36,76 +38,78 @@ export const TableNode: FC = ({ data: { table } }) => { onClick={handleClick} > -
    - {Object.values(table.columns).map((column) => { - const handleId = `${table.name}-${column.name}` - const isSource = Object.values(relationships).some( - (relationship) => - relationship.primaryTableName === table.name && - relationship.primaryColumnName === column.name, - ) - const isTarget = Object.values(relationships).some( - (relationship) => - relationship.foreignTableName === table.name && - relationship.foreignColumnName === column.name, - ) + {showMode === 'ALL_FIELDS' && ( +
      + {Object.values(table.columns).map((column) => { + const handleId = `${table.name}-${column.name}` + const isSource = Object.values(relationships).some( + (relationship) => + relationship.primaryTableName === table.name && + relationship.primaryColumnName === column.name, + ) + const isTarget = Object.values(relationships).some( + (relationship) => + relationship.foreignTableName === table.name && + relationship.foreignColumnName === column.name, + ) - return ( -
    • - {column.primary && ( - - )} - {!column.primary && - (column.notNull ? ( - + {column.primary && ( + - ) : ( - - ))} + )} + {!column.primary && + (column.notNull ? ( + + ) : ( + + ))} - - {column.name} - {column.type} - + + {column.name} + {column.type} + - {isSource && ( - - )} + {isSource && ( + + )} - {isTarget && ( - - )} -
    • - ) - })} -
    + {isTarget && ( + + )} + + ) + })} +
+ )} ) } From 2b33664e8a1a3dab2e8ba124ee383aea2aac1ded Mon Sep 17 00:00:00 2001 From: junkisai Date: Thu, 12 Dec 2024 12:15:19 +0900 Subject: [PATCH 5/5] feat: add base value spacing for elk.layered algorithm --- .../ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts index 17e181959..7527aad53 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/getElkLayout.ts @@ -8,6 +8,7 @@ import { convertNodesToElkNodes } from './convertNodesToElkNodes' const elk = new ELK() const layoutOptions: LayoutOptions = { 'elk.algorithm': 'org.eclipse.elk.layered', + 'elk.layered.spacing.baseValue': '32', } type Params = {