fix(desktop): include more sidebar sessions (#759)

Increase the desktop session list fetch window so noisy observer sessions are less likely to hide real user sessions from the sidebar.

Tested: cd desktop && bun run test -- src/stores/sessionStore.test.ts src/components/layout/Sidebar.test.tsx
Tested: bun run check:desktop
Confidence: high
Scope-risk: narrow
This commit is contained in:
程序员阿江(Relakkes) 2026-06-12 16:43:56 +08:00
parent 90a50eca1c
commit 88d04a6267
2 changed files with 59 additions and 13 deletions

View File

@ -21,6 +21,20 @@ import { useTabStore } from './tabStore'
const initialState = useSessionStore.getState()
function makeSession(id: string, modifiedAt: string, title = id) {
return {
id,
title,
createdAt: modifiedAt,
modifiedAt,
messageCount: 1,
projectPath: '/workspace/project',
projectRoot: '/workspace/project',
workDir: '/workspace/project',
workDirExists: true,
}
}
function delay(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
@ -136,6 +150,17 @@ describe('sessionStore', () => {
expect(useTabStore.getState().tabs[0]?.title).toBe('使用bash写一个shell随便写点什么东西')
})
it('requests a large default session page for noisy history directories', async () => {
listMock.mockResolvedValue({
sessions: [makeSession('session-newest', '2026-05-07T00:00:03.000Z')],
total: 474,
})
await useSessionStore.getState().fetchSessions()
expect(listMock).toHaveBeenCalledWith({ limit: 400 })
})
it('ignores stale session list responses when a newer refresh finishes first', async () => {
const slow = createDeferred<{
sessions: Array<{

View File

@ -11,6 +11,8 @@ import type { SessionListItem } from '../types/session'
import type { PermissionMode } from '../types/settings'
import { isPlaceholderSessionTitle } from '../lib/sessionTitle'
const SESSION_LIST_LIMIT = 400
type CreateSessionOptions = {
repository?: CreateSessionRepositoryOptions
permissionMode?: PermissionMode
@ -61,22 +63,11 @@ export const useSessionStore = create<SessionStore>((set, get) => ({
const requestId = ++fetchSessionsRequestId
set({ isLoading: true, error: null })
try {
const { sessions: raw } = await sessionsApi.list({ project, limit: 100 })
const { sessions: raw } = await sessionsApi.list(buildSessionListParams(project))
if (requestId !== fetchSessionsRequestId) return
let syncedSessions: SessionListItem[] = []
set((state) => {
const currentById = new Map(state.sessions.map((session) => [session.id, session]))
// Deduplicate by session ID - keep the most recently modified entry.
const byId = new Map<string, SessionListItem>()
for (const s of raw) {
const current = currentById.get(s.id)
const candidate = preserveLocalTitle(current, s)
const existing = byId.get(s.id)
if (!existing || new Date(candidate.modifiedAt) > new Date(existing.modifiedAt)) {
byId.set(s.id, candidate)
}
}
const sessions = [...byId.values()]
const sessions = mergeSessionList(raw, state.sessions)
syncedSessions = sessions
return { sessions, isLoading: false }
})
@ -237,6 +228,36 @@ function removeIdsFromSet(selected: Set<string>, ids: string[]): Set<string> {
return next
}
function buildSessionListParams(project: string | undefined) {
return project
? { project, limit: SESSION_LIST_LIMIT }
: { limit: SESSION_LIST_LIMIT }
}
function mergeSessionList(
incoming: SessionListItem[],
currentForTitle: SessionListItem[],
): SessionListItem[] {
const currentById = new Map(currentForTitle.map((session) => [session.id, session]))
const byId = new Map<string, SessionListItem>()
for (const item of incoming) {
const current = currentById.get(item.id)
const candidate = preserveLocalTitle(current, item)
const existing = byId.get(candidate.id)
if (!existing || sessionModifiedTime(candidate) > sessionModifiedTime(existing)) {
byId.set(candidate.id, candidate)
}
}
return [...byId.values()].sort((a, b) => sessionModifiedTime(b) - sessionModifiedTime(a))
}
function sessionModifiedTime(session: SessionListItem): number {
const timestamp = new Date(session.modifiedAt).getTime()
return Number.isFinite(timestamp) ? timestamp : 0
}
function preserveLocalTitle(
current: SessionListItem | undefined,
incoming: SessionListItem,