diff --git a/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.test.tsx b/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.test.tsx
index 92f21f0136..d761efd2cc 100644
--- a/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.test.tsx
+++ b/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.test.tsx
@@ -258,6 +258,50 @@ describe("AgentsSidebar load-more behavior", () => {
expect(onLoadMore).toHaveBeenCalledTimes(1);
});
+ it("recreates the observer when isFetchingNextPage transitions to false so visible sentinels re-trigger", () => {
+ const onLoadMore = vi.fn();
+ const { rerender } = render(
+
+
+ ,
+ );
+
+ const countAfterMount = observeCount;
+ expect(countAfterMount).toBe(1);
+
+ // Start fetching — observer is torn down.
+ rerender(
+
+
+ ,
+ );
+
+ // Fetch completes — a fresh observer is created, firing
+ // an initial entry that detects the still-visible sentinel.
+ rerender(
+
+
+ ,
+ );
+
+ expect(observeCount).toBe(countAfterMount + 1);
+ });
+
it("does NOT render the sentinel when hasNextPage is false", () => {
const onLoadMore = vi.fn();
render(
diff --git a/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx b/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx
index 2dd13a9181..6841ac9d12 100644
--- a/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx
+++ b/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx
@@ -1131,27 +1131,29 @@ const LoadMoreSentinel: FC<{
}> = ({ onLoadMore, isFetchingNextPage }) => {
const sentinelRef = useRef(null);
const onLoadMoreRef = useRef(onLoadMore);
- const isFetchingNextPageRef = useRef(isFetchingNextPage);
- // Keep refs in sync with the latest prop values so the
- // observer callback always reads current state without
- // needing to tear down and re-create the observer.
+ // Keep the callback ref in sync so the observer closure
+ // always calls the latest onLoadMore without needing to
+ // tear down and re-create the observer.
useEffect(() => {
onLoadMoreRef.current = onLoadMore;
- isFetchingNextPageRef.current = isFetchingNextPage;
- }, [onLoadMore, isFetchingNextPage]);
+ }, [onLoadMore]);
useEffect(() => {
+ // Don't observe while a fetch is in progress. When the
+ // fetch completes this effect re-runs, creating a fresh
+ // observer whose initial entry detects the sentinel if
+ // it's still visible — fixing the case where loaded items
+ // don't push the sentinel out of view and the previous
+ // observer never re-fires.
+ if (isFetchingNextPage) return;
+
const el = sentinelRef.current;
if (!el) return;
const observer = new IntersectionObserver(
(entries) => {
- if (
- entries[0]?.isIntersecting &&
- !isFetchingNextPageRef.current &&
- onLoadMoreRef.current
- ) {
+ if (entries[0]?.isIntersecting && onLoadMoreRef.current) {
onLoadMoreRef.current();
}
},
@@ -1159,7 +1161,7 @@ const LoadMoreSentinel: FC<{
);
observer.observe(el);
return () => observer.disconnect();
- }, []);
+ }, [isFetchingNextPage]);
return (