From 9b62de28906b55fb19d63777ea3e5e7392379454 Mon Sep 17 00:00:00 2001 From: FunamaYukina Date: Wed, 18 Dec 2024 17:09:08 +0900 Subject: [PATCH 01/13] Resolving the issue of remaining highlights --- frontend/.changeset/forty-berries-hammer.md | 6 + .../ERDRenderer/ERDContent/ERDContent.tsx | 117 ++++++++++++------ 2 files changed, 85 insertions(+), 38 deletions(-) create mode 100644 frontend/.changeset/forty-berries-hammer.md diff --git a/frontend/.changeset/forty-berries-hammer.md b/frontend/.changeset/forty-berries-hammer.md new file mode 100644 index 00000000..06866b0f --- /dev/null +++ b/frontend/.changeset/forty-berries-hammer.md @@ -0,0 +1,6 @@ +--- +"@liam-hq/erd-core": patch +"@liam-hq/cli": patch +--- + +Resolving the issue of remaining highlights diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx index 50c63cad..c7705260 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx @@ -65,6 +65,22 @@ export const isRelatedToTable = ( ) } +const getHighlightedHandles = ( + edges: Edge[], + targetId: string, + nodeId: string, +) => { + const highlightedTargetHandles = edges + .filter((edge) => edge.source === targetId && edge.target === nodeId) + .map((edge) => edge.targetHandle) + + const highlightedSourceHandles = edges + .filter((edge) => edge.target === targetId && edge.source === nodeId) + .map((edge) => edge.sourceHandle) + + return highlightedTargetHandles.concat(highlightedSourceHandles) || [] +} + export const ERDContentInner: FC = ({ nodes: _nodes, edges: _edges, @@ -103,21 +119,18 @@ export const ERDContentInner: FC = ({ const isRelated = isRelatedToTable(relationships, node.id, nodeId) if (isRelated) { - const highlightedTargetHandles = relatedEdges - .filter((edge) => edge.source === nodeId && edge.target === node.id) - .map((edge) => edge.targetHandle) - - const highlightedSourceHandles = relatedEdges - .filter((edge) => edge.target === nodeId && edge.source === node.id) - .map((edge) => edge.sourceHandle) + const highlightedHandles = getHighlightedHandles( + edges, + nodeId, + node.id, + ) return { ...node, data: { ...node.data, isRelated: isRelated, - highlightedHandles: - highlightedTargetHandles.concat(highlightedSourceHandles) || [], + highlightedHandles: highlightedHandles, }, } } @@ -164,44 +177,82 @@ export const ERDContentInner: FC = ({ (e) => e.source === id || e.target === id, ) - const updatedEdges = edges.map((e) => - relatedEdges.includes(e) ? highlightEdge(e) : e, + const relatedToActiveNodeEdges = edges.filter( + (e) => e.source === activeNodeId || e.target === activeNodeId, ) + const updatedEdges = edges.map((e) => { + if (relatedEdges.includes(e)) { + return highlightEdge(e) + } + if (relatedToActiveNodeEdges.includes(e)) { + return highlightEdge(e) + } + return unhighlightEdge(e) + }) + const updatedNodes = nodes.map((node) => { if (node.id === id) { return { ...node, data: { ...node.data, isHighlighted: true } } } const isRelated = isRelatedToTable(relationships, node.id, id) + const isRelatedToActiveNode = + activeNodeId && isRelatedToTable(relationships, node.id, activeNodeId) if (isRelated) { - const highlightedTargetHandles = relatedEdges - .filter((edge) => edge.source === id && edge.target === node.id) - .map((edge) => edge.targetHandle) + let highlightedHandles = getHighlightedHandles(edges, id, node.id) + if (isRelatedToActiveNode) { + highlightedHandles = highlightedHandles.concat( + getHighlightedHandles(edges, activeNodeId, node.id), + ) + } + + return { + ...node, + data: { + ...node.data, + isRelated: true, + highlightedHandles: highlightedHandles, + }, + } + } - const highlightedSourceHandles = relatedEdges - .filter((edge) => edge.target === id && edge.source === node.id) - .map((edge) => edge.sourceHandle) + if (isRelatedToActiveNode) { + const highlightedHandles = getHighlightedHandles( + edges, + activeNodeId, + node.id, + ).concat(getHighlightedHandles(edges, id, node.id)) + + const isHighlighted = node.id === activeNodeId return { ...node, data: { ...node.data, - isRelated: isRelated, - highlightedHandles: - highlightedTargetHandles.concat(highlightedSourceHandles) || [], + isRelated: true, + isHighlighted: isHighlighted, + highlightedHandles: highlightedHandles, }, } } - return node + return { + ...node, + data: { + ...node.data, + isRelated: false, + isHighlighted: false, + highlightedHandles: [], + }, + } }) setEdges(updatedEdges) setNodes(updatedNodes) }, - [edges, nodes, setNodes, setEdges, relationships], + [edges, nodes, setNodes, setEdges, relationships, activeNodeId], ) const handleMouseLeaveNode: NodeMouseHandler = useCallback( @@ -224,19 +275,11 @@ export const ERDContentInner: FC = ({ ) if (node.id === activeNodeId || isRelated) { - const highlightedTargetHandles = relatedEdges - .filter( - (edge) => - edge.source === activeNodeId && edge.target === node.id, - ) - .map((edge) => edge.targetHandle) - - const highlightedSourceHandles = relatedEdges - .filter( - (edge) => - edge.target === activeNodeId && edge.source === node.id, - ) - .map((edge) => edge.sourceHandle) + const highlightedHandles = getHighlightedHandles( + edges, + activeNodeId, + node.id, + ) const isHighlighted = node.id === activeNodeId @@ -246,9 +289,7 @@ export const ERDContentInner: FC = ({ ...node.data, isRelated: isRelated, isHighlighted: isHighlighted, - highlightedHandles: - highlightedTargetHandles.concat(highlightedSourceHandles) || - [], + highlightedHandles: highlightedHandles, }, } } From c0b2d012ea18445c0cc04f60ed394313b5e72648 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 17:53:44 +0900 Subject: [PATCH 02/13] refactor Integrated `isRelated` into `isHighlighted` --- frontend/.changeset/tricky-comics-raise.md | 6 ++++++ .../components/ERDRenderer/ERDContent/ERDContent.tsx | 11 +++-------- .../ERDContent/TableNode/TableNode.module.css | 2 +- .../ERDRenderer/ERDContent/TableNode/TableNode.tsx | 6 +++--- .../ERDRenderer/ERDContent/TableNode/type.ts | 1 - 5 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 frontend/.changeset/tricky-comics-raise.md diff --git a/frontend/.changeset/tricky-comics-raise.md b/frontend/.changeset/tricky-comics-raise.md new file mode 100644 index 00000000..dbdf5e0f --- /dev/null +++ b/frontend/.changeset/tricky-comics-raise.md @@ -0,0 +1,6 @@ +--- +"@liam-hq/erd-core": patch +"@liam-hq/cli": patch +--- + +refactor Integrated `isRelated` into `isHighlighted` diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx index 8de172f3..18695f72 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx @@ -119,7 +119,7 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: isRelated, + isHighlighted: true, highlightedHandles: highlightedTargetHandles.concat(highlightedSourceHandles) || [], }, @@ -130,7 +130,6 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: false, isHighlighted: false, highlightedHandles: [], }, @@ -152,7 +151,6 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: false, highlightedHandles: [], isHighlighted: false, }, @@ -192,7 +190,7 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: isRelated, + isHighlighted: true, highlightedHandles: highlightedTargetHandles.concat(highlightedSourceHandles) || [], }, @@ -248,8 +246,7 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: isRelated, - isHighlighted: isHighlighted, + isHighlighted, highlightedHandles: highlightedTargetHandles.concat(highlightedSourceHandles) || [], @@ -261,7 +258,6 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: false, isHighlighted: false, highlightedHandles: [], }, @@ -279,7 +275,6 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: false, highlightedHandles: [], isHighlighted: false, }, diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableNode.module.css b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableNode.module.css index 1ae1a2fa..ec87d7c0 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableNode.module.css +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/TableNode.module.css @@ -12,7 +12,7 @@ opacity: 0; } -.wrapperHover, +.wrapperHighlighted, .wrapper:hover { border: 1px solid var(--primary-accent); box-shadow: 0px 0px 20px 0px rgba(29, 237, 131, 0.4); 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 d270a9b3..2df196d2 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 @@ -22,15 +22,15 @@ export const TableNode: FC = ({ data }) => { const isActive = tableName === data.table.name - const isTableRelated = - data.isRelated || + const isTableHighlighted = + data.isHighlighted || isRelatedToTable(relationships, data.table.name, tableName) return (
Date: Wed, 18 Dec 2024 17:21:21 +0900 Subject: [PATCH 03/13] maintenance: add Vitest configuration for testing with path alias --- frontend/packages/erd-core/vitest.config.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 frontend/packages/erd-core/vitest.config.ts diff --git a/frontend/packages/erd-core/vitest.config.ts b/frontend/packages/erd-core/vitest.config.ts new file mode 100644 index 00000000..058a4169 --- /dev/null +++ b/frontend/packages/erd-core/vitest.config.ts @@ -0,0 +1,10 @@ +import * as path from 'node:path' +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, +}) From 8b6a84dd8b95a6fe35c7fd000faaffc0a770cfd8 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 17:29:49 +0900 Subject: [PATCH 04/13] feat: add isActiveHighlighted property to Data type in TableNode --- .../src/components/ERDRenderer/ERDContent/TableNode/type.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/type.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/type.ts index a2cc21e2..ab291053 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/type.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/TableNode/type.ts @@ -3,6 +3,7 @@ import type { Node } from '@xyflow/react' export type Data = { table: Table + isActiveHighlighted: boolean isHighlighted: boolean highlightedHandles: string[] sourceColumnName: string | undefined From f7a729053f02d113647a14a9764605d868b6d37d Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 17:29:59 +0900 Subject: [PATCH 05/13] feat: implement highlightNodesAndEdges function and corresponding tests --- .../ERDContent/highlightNodesAndEdges.test.ts | 67 +++++++++++++++++++ .../ERDContent/highlightNodesAndEdges.ts | 48 +++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts create mode 100644 frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts new file mode 100644 index 00000000..f5556502 --- /dev/null +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts @@ -0,0 +1,67 @@ +import { aTable } from '@liam-hq/db-structure' +import type { Edge } from '@xyflow/react' +import { describe, expect, it } from 'vitest' +import type { Data, TableNodeType } from './TableNode' +import { highlightNodesAndEdges } from './highlightNodesAndEdges' + +const aTableData = (name: string, override?: Partial): Data => ({ + table: aTable({ name }), + isActiveHighlighted: false, + isHighlighted: false, + isRelated: false, + highlightedHandles: [], + sourceColumnName: undefined, + ...override, +}) + +const aTableNode = ( + name: string, + override?: Partial, +): TableNodeType => ({ + id: name, + type: 'table', + position: { x: 0, y: 0 }, + ...override, + data: aTableData(name, override?.data), +}) + +const anEdge = ( + source: string, + target: string, + override?: Partial, +): Edge => ({ + id: `${source}-${target}`, + source, + target, + animated: false, + data: { isHighlighted: false, ...override?.data }, + ...override, +}) + +describe(highlightNodesAndEdges, () => { + const nodes: TableNodeType[] = [ + aTableNode('users'), + aTableNode('posts'), + aTableNode('comments'), + aTableNode('comment_users'), + ] + + const edges: Edge[] = [ + anEdge('users', 'posts'), + anEdge('users', 'comment_users'), + anEdge('comments', 'comment_users'), + ] + + it('When the users is active, the users and related tables are highlighted', () => { + const { nodes: updatedNodes } = highlightNodesAndEdges(nodes, edges, 'users') + + expect(updatedNodes).toEqual([ + aTableNode('users', { + data: aTableData('users', { isActiveHighlighted: true }), + }), + aTableNode('posts'), + aTableNode('comments'), + aTableNode('comment_users'), + ]) + }) +}) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts new file mode 100644 index 00000000..4f7acf27 --- /dev/null +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts @@ -0,0 +1,48 @@ +import type { Edge, Node } from '@xyflow/react' +import { type TableNodeType, isTableNode } from './TableNode' + +const isActiveNode = ( + activeTableName: string | undefined, + node: TableNodeType, +): boolean => { + return node.data.table.name === activeTableName +} + +const activeHighlightNode = (node: TableNodeType): TableNodeType => ({ + ...node, + data: { + ...node.data, + isActiveHighlighted: true, + }, +}) + +const unhighlightNode = (node: TableNodeType): TableNodeType => ({ + ...node, + data: { + ...node.data, + isActiveHighlighted: false, + isHighlighted: false, + isRelated: false, + highlightedHandles: [], + }, +}) + +export const highlightNodesAndEdges = ( + nodes: Node[], + _edges: Edge[], + activeTableName?: string | undefined, +): { nodes: Node[]; edges: Edge[] } => { + const updatedNodes = nodes.map((node) => { + if (!isTableNode(node)) { + return node + } + + if (isActiveNode(activeTableName, node)) { + return activeHighlightNode(node) + } + + return unhighlightNode(node) + }) + + return { nodes: updatedNodes, edges: [] } +} From 38edd853b7fade8fc719c6b8fd5de07fdeb9af24 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 17:43:40 +0900 Subject: [PATCH 06/13] feat: enhance highlightNodesAndEdges function to support active and related node highlighting --- .../ERDContent/highlightNodesAndEdges.test.ts | 14 +++++-- .../ERDContent/highlightNodesAndEdges.ts | 40 ++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts index f5556502..4423168e 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts @@ -53,15 +53,23 @@ describe(highlightNodesAndEdges, () => { ] it('When the users is active, the users and related tables are highlighted', () => { - const { nodes: updatedNodes } = highlightNodesAndEdges(nodes, edges, 'users') + const { nodes: updatedNodes } = highlightNodesAndEdges( + nodes, + edges, + 'users', + ) expect(updatedNodes).toEqual([ aTableNode('users', { data: aTableData('users', { isActiveHighlighted: true }), }), - aTableNode('posts'), + aTableNode('posts', { + data: aTableData('posts', { isHighlighted: true }), + }), aTableNode('comments'), - aTableNode('comment_users'), + aTableNode('comment_users', { + data: aTableData('comment_users', { isHighlighted: true }), + }), ]) }) }) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts index 4f7acf27..80b8eb76 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts @@ -1,6 +1,10 @@ import type { Edge, Node } from '@xyflow/react' import { type TableNodeType, isTableNode } from './TableNode' +type SourceTableName = string +type TargetTableName = string +type EdgeMap = Map + const isActiveNode = ( activeTableName: string | undefined, node: TableNodeType, @@ -8,6 +12,18 @@ const isActiveNode = ( return node.data.table.name === activeTableName } +const isActivelyRelatedNode = ( + activeTableName: string | undefined, + edgeMap: EdgeMap, + node: TableNodeType, +): boolean => { + if (!activeTableName) { + return false + } + + return edgeMap.get(activeTableName)?.includes(node.data.table.name) ?? false +} + const activeHighlightNode = (node: TableNodeType): TableNodeType => ({ ...node, data: { @@ -16,6 +32,14 @@ const activeHighlightNode = (node: TableNodeType): TableNodeType => ({ }, }) +const highlightNode = (node: TableNodeType): TableNodeType => ({ + ...node, + data: { + ...node.data, + isHighlighted: true, + }, +}) + const unhighlightNode = (node: TableNodeType): TableNodeType => ({ ...node, data: { @@ -29,9 +53,19 @@ const unhighlightNode = (node: TableNodeType): TableNodeType => ({ export const highlightNodesAndEdges = ( nodes: Node[], - _edges: Edge[], + edges: Edge[], activeTableName?: string | undefined, ): { nodes: Node[]; edges: Edge[] } => { + const edgeMap: EdgeMap = new Map() + for (const edge of edges) { + const sourceTableName = edge.source + const targetTableName = edge.target + if (!edgeMap.has(sourceTableName)) { + edgeMap.set(sourceTableName, []) + } + edgeMap.get(sourceTableName)?.push(targetTableName) + } + const updatedNodes = nodes.map((node) => { if (!isTableNode(node)) { return node @@ -41,6 +75,10 @@ export const highlightNodesAndEdges = ( return activeHighlightNode(node) } + if (isActivelyRelatedNode(activeTableName, edgeMap, node)) { + return highlightNode(node) + } + return unhighlightNode(node) }) From 428915420170ddc291ae8655e4efb705735fed59 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 17:56:39 +0900 Subject: [PATCH 07/13] refactor: remove unused property --- .../ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts | 1 - .../components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts index 4423168e..3bfddf93 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts @@ -8,7 +8,6 @@ const aTableData = (name: string, override?: Partial): Data => ({ table: aTable({ name }), isActiveHighlighted: false, isHighlighted: false, - isRelated: false, highlightedHandles: [], sourceColumnName: undefined, ...override, diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts index 80b8eb76..56708546 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts @@ -46,7 +46,6 @@ const unhighlightNode = (node: TableNodeType): TableNodeType => ({ ...node.data, isActiveHighlighted: false, isHighlighted: false, - isRelated: false, highlightedHandles: [], }, }) From 99ee55be72a8d4ec496c62712a5b300dd2c21253 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 18:20:59 +0900 Subject: [PATCH 08/13] feat: enhance highlightNodesAndEdges function to include source and target handles for related nodes --- .../ERDContent/highlightNodesAndEdges.test.ts | 25 ++++++++-- .../ERDContent/highlightNodesAndEdges.ts | 46 ++++++++++++++++++- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts index 3bfddf93..be2f19bd 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts @@ -27,11 +27,15 @@ const aTableNode = ( const anEdge = ( source: string, target: string, + sourceHandle: string | null, + targetHandle: string | null, override?: Partial, ): Edge => ({ id: `${source}-${target}`, source, + sourceHandle, target, + targetHandle, animated: false, data: { isHighlighted: false, ...override?.data }, ...override, @@ -46,9 +50,14 @@ describe(highlightNodesAndEdges, () => { ] const edges: Edge[] = [ - anEdge('users', 'posts'), - anEdge('users', 'comment_users'), - anEdge('comments', 'comment_users'), + anEdge('users', 'posts', 'users-id', 'posts-user_id'), + anEdge('users', 'comment_users', 'users-id', 'comment_users-user_id'), + anEdge( + 'comments', + 'comment_users', + 'comments-id', + 'comment_users-comment_id', + ), ] it('When the users is active, the users and related tables are highlighted', () => { @@ -63,11 +72,17 @@ describe(highlightNodesAndEdges, () => { data: aTableData('users', { isActiveHighlighted: true }), }), aTableNode('posts', { - data: aTableData('posts', { isHighlighted: true }), + data: aTableData('posts', { + isHighlighted: true, + highlightedHandles: ['posts-user_id'], + }), }), aTableNode('comments'), aTableNode('comment_users', { - data: aTableData('comment_users', { isHighlighted: true }), + data: aTableData('comment_users', { + isHighlighted: true, + highlightedHandles: ['comment_users-user_id'], + }), }), ]) }) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts index 56708546..cc56e2ac 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.ts @@ -24,6 +24,39 @@ const isActivelyRelatedNode = ( return edgeMap.get(activeTableName)?.includes(node.data.table.name) ?? false } +const getHighlightedHandlesForRelatedNode = ( + activeTableName: string | undefined, + edges: Edge[], + node: TableNodeType, +): string[] => { + if (!activeTableName) { + return [] + } + + const handles: string[] = [] + for (const edge of edges) { + if ( + edge.targetHandle !== undefined && + edge.targetHandle !== null && + edge.source === activeTableName && + edge.target === node.data.table.name + ) { + handles.push(edge.targetHandle) + } + + if ( + edge.sourceHandle !== undefined && + edge.sourceHandle !== null && + edge.source === node.data.table.name && + edge.target === activeTableName + ) { + handles.push(edge.sourceHandle) + } + } + + return handles +} + const activeHighlightNode = (node: TableNodeType): TableNodeType => ({ ...node, data: { @@ -32,11 +65,15 @@ const activeHighlightNode = (node: TableNodeType): TableNodeType => ({ }, }) -const highlightNode = (node: TableNodeType): TableNodeType => ({ +const highlightNode = ( + node: TableNodeType, + handles: string[], +): TableNodeType => ({ ...node, data: { ...node.data, isHighlighted: true, + highlightedHandles: handles, }, }) @@ -75,7 +112,12 @@ export const highlightNodesAndEdges = ( } if (isActivelyRelatedNode(activeTableName, edgeMap, node)) { - return highlightNode(node) + const highlightedHandles = getHighlightedHandlesForRelatedNode( + activeTableName, + edges, + node, + ) + return highlightNode(node, highlightedHandles) } return unhighlightNode(node) From 5260dc6e583fcf3662ebc9e5b2f472f57ddc8dde Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 18:27:07 +0900 Subject: [PATCH 09/13] test: add case to highlightNodesAndEdges for no active table scenario --- .../ERDContent/highlightNodesAndEdges.test.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts index be2f19bd..b61a476b 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/highlightNodesAndEdges.test.ts @@ -86,4 +86,31 @@ describe(highlightNodesAndEdges, () => { }), ]) }) + + it('When no active table, no tables are highlighted', () => { + const { nodes: updatedNodes } = highlightNodesAndEdges( + nodes, + edges, + undefined, + ) + + expect(updatedNodes).toEqual([ + aTableNode('users', { + data: aTableData('users', { isActiveHighlighted: false }), + }), + aTableNode('posts', { + data: aTableData('posts', { + isHighlighted: false, + highlightedHandles: [], + }), + }), + aTableNode('comments'), + aTableNode('comment_users', { + data: aTableData('comment_users', { + isHighlighted: false, + highlightedHandles: [], + }), + }), + ]) + }) }) From a6669be0556cf062f6bfcaa2b96a510c95a905b2 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 18:27:32 +0900 Subject: [PATCH 10/13] refactor: integrate highlightNodesAndEdges function for node and edge highlighting --- .../ERDRenderer/ERDContent/ERDContent.tsx | 58 +++++-------------- 1 file changed, 13 insertions(+), 45 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx index 18695f72..26801981 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx @@ -16,6 +16,7 @@ import { ERDContentProvider, useERDContentContext } from './ERDContentContext' import { RelationshipEdge } from './RelationshipEdge' import { Spinner } from './Spinner' import { TableNode } from './TableNode' +import { highlightNodesAndEdges } from './highlightNodesAndEdges' import { useFitViewWhenActiveTableChange } from './useFitViewWhenActiveTableChange' import { useInitialAutoLayout } from './useInitialAutoLayout' import { useUpdateNodeCardinalities } from './useUpdateNodeCardinalities' @@ -99,62 +100,29 @@ export const ERDContentInner: FC = ({ relatedEdges.includes(e) ? highlightEdge(e) : unhighlightEdge(e), ) - const updatedNodes = nodes.map((node) => { - if (node.id === nodeId) { - return { ...node, data: { ...node.data, isHighlighted: true } } - } - - const isRelated = isRelatedToTable(relationships, node.id, nodeId) - - if (isRelated) { - const highlightedTargetHandles = relatedEdges - .filter((edge) => edge.source === nodeId && edge.target === node.id) - .map((edge) => edge.targetHandle) - - const highlightedSourceHandles = relatedEdges - .filter((edge) => edge.target === nodeId && edge.source === node.id) - .map((edge) => edge.sourceHandle) - - return { - ...node, - data: { - ...node.data, - isHighlighted: true, - highlightedHandles: - highlightedTargetHandles.concat(highlightedSourceHandles) || [], - }, - } - } - - return { - ...node, - data: { - ...node.data, - isHighlighted: false, - highlightedHandles: [], - }, - } - }) + const { nodes: updatedNodes } = highlightNodesAndEdges( + nodes, + edges, + nodeId, + ) setEdges(updatedEdges) setNodes(updatedNodes) }, - [edges, nodes, setNodes, setEdges, relationships], + [edges, nodes, setNodes, setEdges], ) const handlePaneClick = useCallback(() => { setActiveNodeId(null) + updateActiveTableName(undefined) const updatedEdges = edges.map(unhighlightEdge) - const updatedNodes = nodes.map((node) => ({ - ...node, - data: { - ...node.data, - highlightedHandles: [], - isHighlighted: false, - }, - })) + const { nodes: updatedNodes } = highlightNodesAndEdges( + nodes, + edges, + undefined, + ) setEdges(updatedEdges) setNodes(updatedNodes) From 5cca50a128efb76f81d7ed8330a54f3904ad10f9 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 18:27:37 +0900 Subject: [PATCH 11/13] chore: add biome-ignore comment for linting in vitest config --- frontend/packages/erd-core/vitest.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/packages/erd-core/vitest.config.ts b/frontend/packages/erd-core/vitest.config.ts index 058a4169..eb9cc4a3 100644 --- a/frontend/packages/erd-core/vitest.config.ts +++ b/frontend/packages/erd-core/vitest.config.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/correctness/noNodejsModules: Because this file is a config file import * as path from 'node:path' import { defineConfig } from 'vitest/config' From d8ff5d532adaf4cce52c31763cbf16db082458c9 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Wed, 18 Dec 2024 18:28:22 +0900 Subject: [PATCH 12/13] maintenance: add changeset --- frontend/.changeset/pink-drinks-applaud.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 frontend/.changeset/pink-drinks-applaud.md diff --git a/frontend/.changeset/pink-drinks-applaud.md b/frontend/.changeset/pink-drinks-applaud.md new file mode 100644 index 00000000..46906268 --- /dev/null +++ b/frontend/.changeset/pink-drinks-applaud.md @@ -0,0 +1,6 @@ +--- +"@liam-hq/erd-core": patch +"@liam-hq/cli": patch +--- + +Refactoring and testing of highlights on active tables From fd422ef8f422c21d00d60fac4123715eee01c3fa Mon Sep 17 00:00:00 2001 From: FunamaYukina Date: Wed, 18 Dec 2024 21:44:36 +0900 Subject: [PATCH 13/13] fix isRelated to isHighlighted --- .../src/components/ERDRenderer/ERDContent/ERDContent.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx index 63ed5cc2..f14f073e 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx @@ -185,7 +185,7 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: true, + isHighlighted: true, highlightedHandles: highlightedHandles, }, } @@ -203,7 +203,6 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: true, isHighlighted: isHighlighted, highlightedHandles: highlightedHandles, }, @@ -214,7 +213,6 @@ export const ERDContentInner: FC = ({ ...node, data: { ...node.data, - isRelated: false, isHighlighted: false, highlightedHandles: [], },