From bed309a3645e9c2586a529f61fc42a7146ee713e Mon Sep 17 00:00:00 2001 From: viettranx Date: Fri, 3 Apr 2026 23:42:43 +0700 Subject: [PATCH] fix(ui,kg): fix graph canvas sizing on agent selection ForceGraph2D was rendering at wrong default dimensions when the KG page first loaded after selecting an agent. Root cause: early return for empty state removed the container div from DOM, so useLayoutEffect couldn't read dimensions on first mount. Fix: always render container div (flex-1 gives it height from parent), show empty state inside it. Use useLayoutEffect for synchronous initial measurement + ResizeObserver for ongoing changes. Gate ForceGraph2D render behind `ready` flag. Also extracted memory-documents-table from memory-page (gap closure). --- ui/web/src/pages/memory/kg-graph-view.tsx | 32 ++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/ui/web/src/pages/memory/kg-graph-view.tsx b/ui/web/src/pages/memory/kg-graph-view.tsx index 0026d9ee..65f50005 100644 --- a/ui/web/src/pages/memory/kg-graph-view.tsx +++ b/ui/web/src/pages/memory/kg-graph-view.tsx @@ -1,4 +1,4 @@ -import { useRef, useMemo, useCallback, useState, useEffect } from "react"; +import { useRef, useMemo, useCallback, useState, useEffect, useLayoutEffect } from "react"; import ForceGraph2D, { type ForceGraphMethods } from "react-force-graph-2d"; import { Maximize2 } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -29,18 +29,33 @@ export function KGGraphView({ entities: allEntities, relations: allRelations, on const [dimensions, setDimensions] = useState({ width: 600, height: 400 }); const [selectedNodeId, setSelectedNodeId] = useState(null); const [nodeLimit, setNodeLimit] = useState(DEFAULT_NODE_LIMIT); + const [ready, setReady] = useState(false); // Double-click detection refs const clickTimerRef = useRef | null>(null); const lastClickRef = useRef(null); - // --- Container sizing via ResizeObserver --- + // --- Container sizing --- + // 1. Synchronous initial read before first paint to avoid wrong-size flash + useLayoutEffect(() => { + const el = containerRef.current; + if (el && el.clientWidth > 0 && el.clientHeight > 0) { + setDimensions({ width: el.clientWidth, height: el.clientHeight }); + setReady(true); + } + }, []); + + // 2. ResizeObserver for ongoing size changes (window resize, sidebar toggle) useEffect(() => { const el = containerRef.current; if (!el) return; const ro = new ResizeObserver(([entry]) => { if (!entry) return; - setDimensions({ width: entry.contentRect.width, height: entry.contentRect.height }); + const { width, height } = entry.contentRect; + if (width > 0 && height > 0) { + setDimensions({ width, height }); + setReady(true); + } }); ro.observe(el); return () => ro.disconnect(); @@ -175,15 +190,14 @@ export function KGGraphView({ entities: allEntities, relations: allRelations, on // No auto zoom — initial view from warmupTicks is already good }, []); - // --- Empty state --- - if (allEntities.length === 0) { - return
{t("kg.graphView.empty")}
; - } + const hasEntities = allEntities.length > 0; return (
- {t("kg.graphView.empty")}
+ ) : ready ? + /> : null}
{/* Stats bar */}