fix(desktop): show every pinned session, however many there are

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.
This commit is contained in:
Brooklyn Nicholson 2026-08-06 21:27:27 -05:00
parent 03b759db86
commit 45f23205d7
3 changed files with 12 additions and 2 deletions

View File

@ -1288,7 +1288,7 @@ export function ChatSidebar({
{!trimmedQuery && (
<SidebarSessionsSection
activeSessionId={activeSidebarSessionId}
contentClassName={cn('flex max-h-[50vh] flex-col gap-px rounded-lg pb-2 pt-1', GROUP_BODY)}
contentClassName="flex flex-col gap-px rounded-lg pb-2 pt-1"
dndSensors={dndSensors}
emptyState={<SidebarPinnedEmptyState />}
label={s.pinned}

View File

@ -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 &&

View File

@ -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":