From 8ff7ee7d759bbbd5871a7b26bf0ad842bfbff7d5 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Mon, 16 Dec 2024 17:39:38 +0900 Subject: [PATCH 1/4] feat: Add initializeComplete state and action to ERDContentContext for layout management --- .../ERDRenderer/ERDContent/ERDContentContext.tsx | 9 +++++++-- .../ERDContent/useAutoLayout/useAutoLayout.ts | 5 +++-- .../ERDRenderer/ERDContent/useInitialAutoLayout.ts | 10 +++++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContentContext.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContentContext.tsx index 9f8b41dd..4158205b 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContentContext.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContentContext.tsx @@ -8,10 +8,12 @@ import { type ERDContentContextState = { loading: boolean + initializeComplete: boolean } type ERDContentContextActions = { setLoading: (loading: boolean) => void + setInitializeComplete: (initializeComplete: boolean) => void } type ERDContentConextValue = { @@ -22,9 +24,11 @@ type ERDContentConextValue = { const ERDContentContext = createContext({ state: { loading: true, + initializeComplete: false, }, actions: { setLoading: () => {}, + setInitializeComplete: () => {}, }, }) @@ -32,12 +36,13 @@ export const useERDContentContext = () => useContext(ERDContentContext) export const ERDContentProvider: FC = ({ children }) => { const [loading, setLoading] = useState(true) + const [initializeComplete, setInitializeComplete] = useState(false) return ( {children} diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/useAutoLayout.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/useAutoLayout.ts index 3aedd8a9..39ffecd5 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/useAutoLayout.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/useAutoLayout.ts @@ -7,7 +7,7 @@ import { getElkLayout } from './getElkLayout' export const useAutoLayout = () => { const { getNodes, setNodes, getEdges, fitView } = useReactFlow() const { - actions: { setLoading }, + actions: { setLoading, setInitializeComplete }, } = useERDContentContext() const handleLayout = useCallback(async () => { @@ -30,8 +30,9 @@ export const useAutoLayout = () => { setNodes([...hiddenNodes, ...newNodes]) setLoading(false) + setInitializeComplete(true) setTimeout(() => fitView(), 0) - }, [getNodes, setNodes, getEdges, fitView, setLoading]) + }, [getNodes, setNodes, getEdges, fitView, setLoading, setInitializeComplete]) return { handleLayout } } diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useInitialAutoLayout.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useInitialAutoLayout.ts index f57f4862..e9c50cec 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useInitialAutoLayout.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useInitialAutoLayout.ts @@ -1,14 +1,22 @@ import { useNodesInitialized } from '@xyflow/react' import { useEffect } from 'react' +import { useERDContentContext } from './ERDContentContext' import { useAutoLayout } from './useAutoLayout' export const useInitialAutoLayout = () => { const nodesInitialized = useNodesInitialized() + const { + state: { initializeComplete }, + } = useERDContentContext() const { handleLayout } = useAutoLayout() useEffect(() => { + if (initializeComplete) { + return + } + if (nodesInitialized) { handleLayout() } - }, [nodesInitialized, handleLayout]) + }, [nodesInitialized, initializeComplete, handleLayout]) } From 9c44a6a274371fb3237e241a2b269f50dc7411f0 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Mon, 16 Dec 2024 18:12:25 +0900 Subject: [PATCH 2/4] fix: Fixed an issue where the correct table was not focused when sharing URLs in TableDetail --- frontend/.changeset/flat-bikes-develop.md | 6 +++ .../ERDContent/useAutoLayout/useAutoLayout.ts | 45 ++++++++++--------- .../ERDContent/useInitialAutoLayout.ts | 18 +++++++- 3 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 frontend/.changeset/flat-bikes-develop.md diff --git a/frontend/.changeset/flat-bikes-develop.md b/frontend/.changeset/flat-bikes-develop.md new file mode 100644 index 00000000..28f47609 --- /dev/null +++ b/frontend/.changeset/flat-bikes-develop.md @@ -0,0 +1,6 @@ +--- +"@liam-hq/erd-core": patch +"@liam-hq/cli": patch +--- + +fix: Fixed an issue where the correct table was not focused when sharing URLs in TableDetail diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/useAutoLayout.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/useAutoLayout.ts index 39ffecd5..1073c6c7 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/useAutoLayout.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useAutoLayout/useAutoLayout.ts @@ -1,5 +1,5 @@ import { useReactFlow } from '@xyflow/react' -import type { Node } from '@xyflow/react' +import type { FitViewOptions, Node } from '@xyflow/react' import { useCallback } from 'react' import { useERDContentContext } from '../ERDContentContext' import { getElkLayout } from './getElkLayout' @@ -10,29 +10,32 @@ export const useAutoLayout = () => { actions: { setLoading, setInitializeComplete }, } = useERDContentContext() - const handleLayout = useCallback(async () => { - setLoading(true) - const nodes = getNodes() - const edges = getEdges() - const visibleNodes: Node[] = nodes.filter((node) => !node.hidden) - const hiddenNodes: Node[] = nodes.filter((node) => node.hidden) + const handleLayout = useCallback( + async (fitViewOptions?: FitViewOptions) => { + setLoading(true) + const nodes = getNodes() + const edges = getEdges() + const visibleNodes: Node[] = nodes.filter((node) => !node.hidden) + const hiddenNodes: Node[] = nodes.filter((node) => node.hidden) - // NOTE: Only include edges where both the source and target are in the nodes - const nodeMap = new Map(visibleNodes.map((node) => [node.id, node])) - const visibleEdges = edges.filter((edge) => { - return nodeMap.get(edge.source) && nodeMap.get(edge.target) - }) + // NOTE: Only include edges where both the source and target are in the nodes + const nodeMap = new Map(visibleNodes.map((node) => [node.id, node])) + const visibleEdges = edges.filter((edge) => { + return nodeMap.get(edge.source) && nodeMap.get(edge.target) + }) - const newNodes = await getElkLayout({ - nodes: visibleNodes, - edges: visibleEdges, - }) + const newNodes = await getElkLayout({ + nodes: visibleNodes, + edges: visibleEdges, + }) - setNodes([...hiddenNodes, ...newNodes]) - setLoading(false) - setInitializeComplete(true) - setTimeout(() => fitView(), 0) - }, [getNodes, setNodes, getEdges, fitView, setLoading, setInitializeComplete]) + setNodes([...hiddenNodes, ...newNodes]) + setLoading(false) + setInitializeComplete(true) + setTimeout(() => fitView(fitViewOptions), 0) + }, + [getNodes, setNodes, getEdges, fitView, setLoading, setInitializeComplete], + ) return { handleLayout } } diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useInitialAutoLayout.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useInitialAutoLayout.ts index e9c50cec..752025a6 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useInitialAutoLayout.ts +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useInitialAutoLayout.ts @@ -1,8 +1,18 @@ +import type { QueryParam } from '@/schemas/queryParam' +import { updateActiveTableName } from '@/stores' import { useNodesInitialized } from '@xyflow/react' import { useEffect } from 'react' import { useERDContentContext } from './ERDContentContext' import { useAutoLayout } from './useAutoLayout' +const getActiveTableNameFromUrl = (): string | undefined => { + const urlParams = new URLSearchParams(window.location.search) + const activeQueryParam: QueryParam = 'active' + const tableName = urlParams.get(activeQueryParam) + + return tableName || undefined +} + export const useInitialAutoLayout = () => { const nodesInitialized = useNodesInitialized() const { @@ -15,8 +25,14 @@ export const useInitialAutoLayout = () => { return } + const tableNameFromUrl = getActiveTableNameFromUrl() + updateActiveTableName(tableNameFromUrl) + const fitViewOptions = tableNameFromUrl + ? { maxZoom: 1, duration: 300, nodes: [{ id: tableNameFromUrl }] } + : undefined + if (nodesInitialized) { - handleLayout() + handleLayout(fitViewOptions) } }, [nodesInitialized, initializeComplete, handleLayout]) } From 19e499a85a527247bf66baac29467f9847535f42 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Mon, 16 Dec 2024 18:13:11 +0900 Subject: [PATCH 3/4] refactor: Remove useActiveTableNameFromUrl hook to streamline ERDContent component --- .../ERDRenderer/ERDContent/ERDContent.tsx | 2 -- .../ERDContent/useActiveTableNameFromUrl.ts | 15 --------------- 2 files changed, 17 deletions(-) delete mode 100644 frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useActiveTableNameFromUrl.ts 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 36f518d4..2b0e1e71 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/ERDContent.tsx @@ -15,7 +15,6 @@ import styles from './ERDContent.module.css' import { ERDContentProvider, useERDContentContext } from './ERDContentContext' import { RelationshipEdge } from './RelationshipEdge' import { TableNode } from './TableNode' -import { useActiveTableNameFromUrl } from './useActiveTableNameFromUrl' import { useFitViewWhenActiveTableChange } from './useFitViewWhenActiveTableChange' import { useInitialAutoLayout } from './useInitialAutoLayout' @@ -67,7 +66,6 @@ export const ERDContentInner: FC = ({ } = useERDContentContext() useInitialAutoLayout() - useActiveTableNameFromUrl() useFitViewWhenActiveTableChange( enabledFeatures?.fitViewWhenActiveTableChange ?? true, ) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useActiveTableNameFromUrl.ts b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useActiveTableNameFromUrl.ts deleted file mode 100644 index 8e96224f..00000000 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/useActiveTableNameFromUrl.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { QueryParam } from '@/schemas/queryParam' -import { updateActiveTableName } from '@/stores' -import { useEffect } from 'react' - -export const useActiveTableNameFromUrl = () => { - useEffect(() => { - const urlParams = new URLSearchParams(window.location.search) - const activeQueryParam: QueryParam = 'active' - const tableFromUrl = urlParams.get(activeQueryParam) - - if (!tableFromUrl) return - - updateActiveTableName(tableFromUrl) - }, []) -} From 4cef3ec857170c72aa810b967515732589a89a64 Mon Sep 17 00:00:00 2001 From: MH4GF Date: Mon, 16 Dec 2024 21:11:04 +0900 Subject: [PATCH 4/4] fix type --- .../ERDContent/Toolbar/TidyUpButton/TidyUpButton.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/Toolbar/TidyUpButton/TidyUpButton.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/Toolbar/TidyUpButton/TidyUpButton.tsx index 7b76cf62..f60179dc 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/Toolbar/TidyUpButton/TidyUpButton.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/ERDContent/Toolbar/TidyUpButton/TidyUpButton.tsx @@ -1,17 +1,20 @@ import { IconButton, TidyUpIcon } from '@liam-hq/ui' import { ToolbarButton } from '@radix-ui/react-toolbar' -import type { FC } from 'react' +import { type FC, useCallback } from 'react' import { useAutoLayout } from '../../useAutoLayout' export const TidyUpButton: FC = () => { const { handleLayout } = useAutoLayout() + const handleClick = useCallback(() => { + handleLayout() + }, [handleLayout]) return ( } tooltipContent="Tidy up" - onClick={handleLayout} + onClick={handleClick} /> )