Skip to content

Commit 077ca44

Browse files
authored
fix(desktop): "load more" button behavior in desktop sidebar (#8430)
1 parent 05cbb11 commit 077ca44

File tree

6 files changed

+62
-4
lines changed

6 files changed

+62
-4
lines changed

packages/app/src/context/global-sync.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type State = {
3838
config: Config
3939
path: Path
4040
session: Session[]
41+
sessionTotal: number
4142
session_status: {
4243
[sessionID: string]: SessionStatus
4344
}
@@ -98,6 +99,7 @@ function createGlobalSync() {
9899
agent: [],
99100
command: [],
100101
session: [],
102+
sessionTotal: 0,
101103
session_status: {},
102104
session_diff: {},
103105
todo: {},
@@ -117,8 +119,10 @@ function createGlobalSync() {
117119

118120
async function loadSessions(directory: string) {
119121
const [store, setStore] = child(directory)
120-
globalSDK.client.session
121-
.list({ directory })
122+
const limit = store.limit
123+
124+
return globalSDK.client.session
125+
.list({ directory, roots: true })
122126
.then((x) => {
123127
const fourHoursAgo = Date.now() - 4 * 60 * 60 * 1000
124128
const nonArchived = (x.data ?? [])
@@ -128,10 +132,12 @@ function createGlobalSync() {
128132
.sort((a, b) => a.id.localeCompare(b.id))
129133
// Include up to the limit, plus any updated in the last 4 hours
130134
const sessions = nonArchived.filter((s, i) => {
131-
if (i < store.limit) return true
135+
if (i < limit) return true
132136
const updated = new Date(s.time?.updated ?? s.time?.created).getTime()
133137
return updated > fourHoursAgo
134138
})
139+
// Store total session count (used for "load more" pagination)
140+
setStore("sessionTotal", nonArchived.length)
135141
setStore("session", reconcile(sessions, { key: "id" }))
136142
})
137143
.catch((err) => {

packages/app/src/pages/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,7 @@ export default function Layout(props: ParentProps) {
944944
.toSorted(sortSessions),
945945
)
946946
const rootSessions = createMemo(() => sessions().filter((s) => !s.parentID))
947-
const hasMoreSessions = createMemo(() => store.session.length >= store.limit)
947+
const hasMoreSessions = createMemo(() => store.sessionTotal > store.session.length)
948948
const loadMoreSessions = async () => {
949949
setProjectStore("limit", (limit) => limit + 5)
950950
await globalSync.project.loadSessions(props.project.worktree)

packages/opencode/src/server/server.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,8 @@ export namespace Server {
724724
validator(
725725
"query",
726726
z.object({
727+
directory: z.string().optional().meta({ description: "Filter sessions by project directory" }),
728+
roots: z.coerce.boolean().optional().meta({ description: "Only return root sessions (no parentID)" }),
727729
start: z.coerce
728730
.number()
729731
.optional()
@@ -737,6 +739,8 @@ export namespace Server {
737739
const term = query.search?.toLowerCase()
738740
const sessions: Session.Info[] = []
739741
for await (const session of Session.list()) {
742+
if (query.directory !== undefined && session.directory !== query.directory) continue
743+
if (query.roots && session.parentID) continue
740744
if (query.start !== undefined && session.time.updated < query.start) continue
741745
if (term !== undefined && !session.title.toLowerCase().includes(term)) continue
742746
sessions.push(session)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { describe, expect, test } from "bun:test"
2+
import path from "path"
3+
import { Instance } from "../../src/project/instance"
4+
import { Server } from "../../src/server/server"
5+
import { Session } from "../../src/session"
6+
import { Log } from "../../src/util/log"
7+
8+
const projectRoot = path.join(__dirname, "../..")
9+
Log.init({ print: false })
10+
11+
describe("session.list", () => {
12+
test("filters by directory", async () => {
13+
await Instance.provide({
14+
directory: projectRoot,
15+
fn: async () => {
16+
const app = Server.App()
17+
18+
const first = await Session.create({})
19+
20+
const otherDir = path.join(projectRoot, "..", "__session_list_other")
21+
const second = await Instance.provide({
22+
directory: otherDir,
23+
fn: async () => Session.create({}),
24+
})
25+
26+
const response = await app.request(`/session?directory=${encodeURIComponent(projectRoot)}`)
27+
expect(response.status).toBe(200)
28+
29+
const body = (await response.json()) as unknown[]
30+
const ids = body
31+
.map((s) => (typeof s === "object" && s && "id" in s ? (s as { id: string }).id : undefined))
32+
.filter((x): x is string => typeof x === "string")
33+
34+
expect(ids).toContain(first.id)
35+
expect(ids).not.toContain(second.id)
36+
},
37+
})
38+
})
39+
})

packages/sdk/js/src/v2/gen/sdk.gen.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,7 @@ export class Session extends HeyApiClient {
781781
public list<ThrowOnError extends boolean = false>(
782782
parameters?: {
783783
directory?: string
784+
roots?: boolean
784785
start?: number
785786
search?: string
786787
limit?: number
@@ -793,6 +794,7 @@ export class Session extends HeyApiClient {
793794
{
794795
args: [
795796
{ in: "query", key: "directory" },
797+
{ in: "query", key: "roots" },
796798
{ in: "query", key: "start" },
797799
{ in: "query", key: "search" },
798800
{ in: "query", key: "limit" },

packages/sdk/js/src/v2/gen/types.gen.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2589,7 +2589,14 @@ export type SessionListData = {
25892589
body?: never
25902590
path?: never
25912591
query?: {
2592+
/**
2593+
* Filter sessions by project directory
2594+
*/
25922595
directory?: string
2596+
/**
2597+
* Only return root sessions (no parentID)
2598+
*/
2599+
roots?: boolean
25932600
/**
25942601
* Filter sessions updated on or after this timestamp (milliseconds since epoch)
25952602
*/

0 commit comments

Comments
 (0)