fix(desktop): stop dropping pinned sessions past the page limit
The list endpoints deliberately back-fill pinned conversations past their LIMIT, then the client sliced the response back down to that same limit and threw them away — so only pins that happened to land inside the most recent page ever rendered, which reads as a cap on how many sessions you can pin. Keep the back-filled rows when trimming, and discount them from the "window came back full" test that drives Load more. Counting a back-fill as a loaded row invented a page that could never be fetched, leaving a Load more button that refetched the same rows forever.
This commit is contained in:
parent
cef7d1a1e1
commit
fd9fc50dd2
|
|
@ -262,8 +262,12 @@ export function useSessionListActions({ profileScope }: UseSessionListActionsArg
|
|||
...mergeSessionPage(prev.filter(inKey), result.sessions, keep)
|
||||
])
|
||||
|
||||
// A full window back means the profile still has more on disk.
|
||||
const truncated = result.sessions.length >= loaded + SIDEBAR_SESSIONS_PAGE_SIZE
|
||||
// A full window back means the profile still has more on disk — but pinned
|
||||
// rows arrive as a back-fill PAST the limit, so counting them fakes a full
|
||||
// page and the "Load more" never goes away (it re-fetches the same rows
|
||||
// forever). Only unpinned rows count toward the window.
|
||||
const unpinned = result.sessions.filter(s => !s.pinned).length
|
||||
const truncated = unpinned >= loaded + SIDEBAR_SESSIONS_PAGE_SIZE
|
||||
setSessionProfilesTruncated(prev => ({ ...prev, [key]: truncated }))
|
||||
}, [])
|
||||
|
||||
|
|
|
|||
|
|
@ -370,6 +370,26 @@ export function pluginSocket(pluginId: string, path: string, onMessage: (data: u
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim a page to its window WITHOUT discarding pinned rows.
|
||||
*
|
||||
* The list endpoints deliberately back-fill pinned conversations past their
|
||||
* LIMIT — a pin means "always reachable", so an aged-out pinned chat is
|
||||
* appended after the recency window. A plain `slice(0, limit)` throws exactly
|
||||
* those rows away again, which is why pins silently stopped rendering past
|
||||
* some count: the sidebar could only ever show the pins that happened to fall
|
||||
* inside the most-recent page.
|
||||
*/
|
||||
function pageWindow(sessions: SessionInfo[], limit: number): SessionInfo[] {
|
||||
if (sessions.length <= limit) {
|
||||
return sessions
|
||||
}
|
||||
|
||||
const recent = sessions.slice(0, limit)
|
||||
|
||||
return [...recent, ...sessions.slice(limit).filter(session => session.pinned)]
|
||||
}
|
||||
|
||||
export async function listSessions(
|
||||
limit = 40,
|
||||
minMessages = 0,
|
||||
|
|
@ -385,7 +405,7 @@ export async function listSessions(
|
|||
|
||||
return {
|
||||
...result,
|
||||
sessions: result.sessions.slice(0, limit),
|
||||
sessions: pageWindow(result.sessions, limit),
|
||||
offset: 0
|
||||
}
|
||||
}
|
||||
|
|
@ -426,7 +446,7 @@ export async function listAllProfileSessions(
|
|||
|
||||
return {
|
||||
...result,
|
||||
sessions: result.sessions.slice(0, limit),
|
||||
sessions: pageWindow(result.sessions, limit),
|
||||
offset: 0
|
||||
}
|
||||
}
|
||||
|
|
@ -445,14 +465,16 @@ export interface SidebarSessionSlice {
|
|||
|
||||
/** Which profiles filled their per-profile window in a returned page. The
|
||||
* legacy per-slice endpoint doesn't report this, so derive it from the rows:
|
||||
* a profile at (or over) the cap still has more on disk. */
|
||||
* a profile at (or over) the cap still has more on disk. Pinned rows are
|
||||
* discounted — they're back-filled past the LIMIT, so counting them fakes a
|
||||
* full page and leaves a "Load more" that can never resolve. */
|
||||
function profilesTruncatedFrom(sessions: SessionInfo[], cap: number): Record<string, boolean> {
|
||||
const counts = new Map<string, number>()
|
||||
|
||||
for (const session of sessions) {
|
||||
const key = session.profile || 'default'
|
||||
|
||||
counts.set(key, (counts.get(key) ?? 0) + 1)
|
||||
counts.set(key, (counts.get(key) ?? 0) + (session.pinned ? 0 : 1))
|
||||
}
|
||||
|
||||
return Object.fromEntries([...counts].map(([name, count]) => [name, count >= cap]))
|
||||
|
|
|
|||
Loading…
Reference in New Issue