diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx index e03e0e5a..d1eeaf72 100644 --- a/ui/src/components/LayoutShell.tsx +++ b/ui/src/components/LayoutShell.tsx @@ -5,7 +5,7 @@ import { useRouteCatalog } from '../api/queries/catalog'; import { useAgents } from '../api/queries/agents'; import { useSearchExecutions } from '../api/queries/executions'; import { useAuthStore } from '../auth/auth-store'; -import { useState, useMemo, useCallback, useEffect } from 'react'; +import { useState, useMemo, useCallback, useEffect, useRef } from 'react'; import { ContentTabs } from './ContentTabs'; import { useScope } from '../hooks/useScope'; @@ -145,6 +145,13 @@ function LayoutContent() { [catalog, agents], ); + // Stable reference for catalog data — only changes when catalog/agents actually change, + // not on every poll cycle (prevents cmd-k scroll reset) + const catalogRef = useRef(catalogData); + if (catalogData !== catalogRef.current && JSON.stringify(catalogData) !== JSON.stringify(catalogRef.current)) { + catalogRef.current = catalogData; + } + const searchData: SearchResult[] = useMemo(() => { const exchangeItems: SearchResult[] = (exchangeResults?.data || []).map((e: any) => ({ id: e.executionId, @@ -178,8 +185,8 @@ function LayoutContent() { } } - return [...catalogData, ...exchangeItems, ...attributeItems]; - }, [catalogData, exchangeResults, debouncedQuery]); + return [...catalogRef.current, ...exchangeItems, ...attributeItems]; + }, [catalogRef.current, exchangeResults, debouncedQuery]); const isAdminPage = location.pathname.startsWith('/admin'); const breadcrumb = useMemo(() => {