From 45f23205d790d65762dae6dd75d24e2124e1cbb0 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Thu, 6 Aug 2026 21:27:27 -0500 Subject: [PATCH] fix(desktop): show every pinned session, however many there are MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pinned was capped at half the viewport by its own nested scroller, so past roughly a dozen pins the rest were reachable only by scrolling inside a scroller — a pin you have to go hunting for isn't doing its job. Drop the cap and let the section grow into the sidebar's existing scroll, and stop virtualizing Pinned: virtualization needs a bounded viewport to measure against, which is exactly what's being removed. No count badge, no "show more" — pin as many as you want and they all render. Also back-fill pins on the API-server list route, which was the one list path still windowing purely on recency. --- apps/desktop/src/app/chat/sidebar/index.tsx | 2 +- apps/desktop/src/app/chat/sidebar/sessions-section.tsx | 4 ++++ gateway/platforms/api_server.py | 8 +++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx index 98c4f312ede53..91f8abcdc45bf 100644 --- a/apps/desktop/src/app/chat/sidebar/index.tsx +++ b/apps/desktop/src/app/chat/sidebar/index.tsx @@ -1288,7 +1288,7 @@ export function ChatSidebar({ {!trimmedQuery && ( } label={s.pinned} diff --git a/apps/desktop/src/app/chat/sidebar/sessions-section.tsx b/apps/desktop/src/app/chat/sidebar/sessions-section.tsx index 37d6be115559f..12ba16134f6d5 100644 --- a/apps/desktop/src/app/chat/sidebar/sessions-section.tsx +++ b/apps/desktop/src/app/chat/sidebar/sessions-section.tsx @@ -313,7 +313,11 @@ export function SidebarSessionsSection({ // wasn't looking at — the drag that landed a row in the wrong slot. const sortableRowIds = useMemo(() => reorderableRowIds(flatRows), [flatRows]) + // Pinned never virtualizes. Virtualization needs a bounded viewport to + // measure against, and Pinned deliberately has none — however many chats you + // pin, all of them render and the sidebar's own scroll carries the length. const flatVirtualized = + !pinned && !showEmptyState && !groups?.length && !projectOverview?.length && diff --git a/gateway/platforms/api_server.py b/gateway/platforms/api_server.py index 0f0dff5fbbc77..24cc8f1bca55d 100644 --- a/gateway/platforms/api_server.py +++ b/gateway/platforms/api_server.py @@ -3279,13 +3279,19 @@ class APIServerAdapter(BasePlatformAdapter): offset=offset, include_children=include_children, order_by_last_active=True, + # A pin means "always reachable", so a pinned conversation that has + # aged past the recency window is back-filled rather than dropped. + include_pinned=True, ) + # Back-filled pins arrive PAST the limit, so counting them would report + # another page that doesn't exist. Only the recency window decides. + windowed = sum(1 for s in sessions if not s.get("pinned")) return web.json_response({ "object": "list", "data": [self._session_response(s) for s in sessions], "limit": limit, "offset": offset, - "has_more": len(sessions) == limit, + "has_more": windowed >= limit, }) async def _handle_create_session(self, request: "web.Request") -> "web.Response":