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/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/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/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} /> ) 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) - }, []) -} 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..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' @@ -7,31 +7,35 @@ import { getElkLayout } from './getElkLayout' export const useAutoLayout = () => { const { getNodes, setNodes, getEdges, fitView } = useReactFlow() const { - actions: { setLoading }, + 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) - setTimeout(() => fitView(), 0) - }, [getNodes, setNodes, getEdges, fitView, setLoading]) + 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 f57f4862..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,14 +1,38 @@ +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 { + state: { initializeComplete }, + } = useERDContentContext() const { handleLayout } = useAutoLayout() useEffect(() => { + if (initializeComplete) { + return + } + + const tableNameFromUrl = getActiveTableNameFromUrl() + updateActiveTableName(tableNameFromUrl) + const fitViewOptions = tableNameFromUrl + ? { maxZoom: 1, duration: 300, nodes: [{ id: tableNameFromUrl }] } + : undefined + if (nodesInitialized) { - handleLayout() + handleLayout(fitViewOptions) } - }, [nodesInitialized, handleLayout]) + }, [nodesInitialized, initializeComplete, handleLayout]) }