summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorShane Bishop <[email protected]>2026-01-14 05:36:08 -0800
committerGitHub <[email protected]>2026-01-14 07:36:08 -0600
commit077ca4454f152176328496bf0ab3b3d44c2fba9d (patch)
treeb7ac3970dc65a4cc481f8a98f4fe552cd47fa5ff
parent05cbb11709de3d05623fee83fdb9c255471389e9 (diff)
downloadopencode-077ca4454f152176328496bf0ab3b3d44c2fba9d.tar.gz
opencode-077ca4454f152176328496bf0ab3b3d44c2fba9d.zip
fix(desktop): "load more" button behavior in desktop sidebar (#8430)
-rw-r--r--packages/app/src/context/global-sync.tsx12
-rw-r--r--packages/app/src/pages/layout.tsx2
-rw-r--r--packages/opencode/src/server/server.ts4
-rw-r--r--packages/opencode/test/server/session-list.test.ts39
-rw-r--r--packages/sdk/js/src/v2/gen/sdk.gen.ts2
-rw-r--r--packages/sdk/js/src/v2/gen/types.gen.ts7
6 files changed, 62 insertions, 4 deletions
diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx
index c11edd292..ea0b90d5d 100644
--- a/packages/app/src/context/global-sync.tsx
+++ b/packages/app/src/context/global-sync.tsx
@@ -38,6 +38,7 @@ type State = {
config: Config
path: Path
session: Session[]
+ sessionTotal: number
session_status: {
[sessionID: string]: SessionStatus
}
@@ -98,6 +99,7 @@ function createGlobalSync() {
agent: [],
command: [],
session: [],
+ sessionTotal: 0,
session_status: {},
session_diff: {},
todo: {},
@@ -117,8 +119,10 @@ function createGlobalSync() {
async function loadSessions(directory: string) {
const [store, setStore] = child(directory)
- globalSDK.client.session
- .list({ directory })
+ const limit = store.limit
+
+ return globalSDK.client.session
+ .list({ directory, roots: true })
.then((x) => {
const fourHoursAgo = Date.now() - 4 * 60 * 60 * 1000
const nonArchived = (x.data ?? [])
@@ -128,10 +132,12 @@ function createGlobalSync() {
.sort((a, b) => a.id.localeCompare(b.id))
// Include up to the limit, plus any updated in the last 4 hours
const sessions = nonArchived.filter((s, i) => {
- if (i < store.limit) return true
+ if (i < limit) return true
const updated = new Date(s.time?.updated ?? s.time?.created).getTime()
return updated > fourHoursAgo
})
+ // Store total session count (used for "load more" pagination)
+ setStore("sessionTotal", nonArchived.length)
setStore("session", reconcile(sessions, { key: "id" }))
})
.catch((err) => {
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx
index cffefd563..39f397ac4 100644
--- a/packages/app/src/pages/layout.tsx
+++ b/packages/app/src/pages/layout.tsx
@@ -944,7 +944,7 @@ export default function Layout(props: ParentProps) {
.toSorted(sortSessions),
)
const rootSessions = createMemo(() => sessions().filter((s) => !s.parentID))
- const hasMoreSessions = createMemo(() => store.session.length >= store.limit)
+ const hasMoreSessions = createMemo(() => store.sessionTotal > store.session.length)
const loadMoreSessions = async () => {
setProjectStore("limit", (limit) => limit + 5)
await globalSync.project.loadSessions(props.project.worktree)
diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts
index 52457515b..7015c8188 100644
--- a/packages/opencode/src/server/server.ts
+++ b/packages/opencode/src/server/server.ts
@@ -724,6 +724,8 @@ export namespace Server {
validator(
"query",
z.object({
+ directory: z.string().optional().meta({ description: "Filter sessions by project directory" }),
+ roots: z.coerce.boolean().optional().meta({ description: "Only return root sessions (no parentID)" }),
start: z.coerce
.number()
.optional()
@@ -737,6 +739,8 @@ export namespace Server {
const term = query.search?.toLowerCase()
const sessions: Session.Info[] = []
for await (const session of Session.list()) {
+ if (query.directory !== undefined && session.directory !== query.directory) continue
+ if (query.roots && session.parentID) continue
if (query.start !== undefined && session.time.updated < query.start) continue
if (term !== undefined && !session.title.toLowerCase().includes(term)) continue
sessions.push(session)
diff --git a/packages/opencode/test/server/session-list.test.ts b/packages/opencode/test/server/session-list.test.ts
new file mode 100644
index 000000000..623c16a81
--- /dev/null
+++ b/packages/opencode/test/server/session-list.test.ts
@@ -0,0 +1,39 @@
+import { describe, expect, test } from "bun:test"
+import path from "path"
+import { Instance } from "../../src/project/instance"
+import { Server } from "../../src/server/server"
+import { Session } from "../../src/session"
+import { Log } from "../../src/util/log"
+
+const projectRoot = path.join(__dirname, "../..")
+Log.init({ print: false })
+
+describe("session.list", () => {
+ test("filters by directory", async () => {
+ await Instance.provide({
+ directory: projectRoot,
+ fn: async () => {
+ const app = Server.App()
+
+ const first = await Session.create({})
+
+ const otherDir = path.join(projectRoot, "..", "__session_list_other")
+ const second = await Instance.provide({
+ directory: otherDir,
+ fn: async () => Session.create({}),
+ })
+
+ const response = await app.request(`/session?directory=${encodeURIComponent(projectRoot)}`)
+ expect(response.status).toBe(200)
+
+ const body = (await response.json()) as unknown[]
+ const ids = body
+ .map((s) => (typeof s === "object" && s && "id" in s ? (s as { id: string }).id : undefined))
+ .filter((x): x is string => typeof x === "string")
+
+ expect(ids).toContain(first.id)
+ expect(ids).not.toContain(second.id)
+ },
+ })
+ })
+})
diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts
index f83913ea5..697dac7ee 100644
--- a/packages/sdk/js/src/v2/gen/sdk.gen.ts
+++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts
@@ -781,6 +781,7 @@ export class Session extends HeyApiClient {
public list<ThrowOnError extends boolean = false>(
parameters?: {
directory?: string
+ roots?: boolean
start?: number
search?: string
limit?: number
@@ -793,6 +794,7 @@ export class Session extends HeyApiClient {
{
args: [
{ in: "query", key: "directory" },
+ { in: "query", key: "roots" },
{ in: "query", key: "start" },
{ in: "query", key: "search" },
{ in: "query", key: "limit" },
diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts
index acc29d9b4..2bb3a6002 100644
--- a/packages/sdk/js/src/v2/gen/types.gen.ts
+++ b/packages/sdk/js/src/v2/gen/types.gen.ts
@@ -2589,8 +2589,15 @@ export type SessionListData = {
body?: never
path?: never
query?: {
+ /**
+ * Filter sessions by project directory
+ */
directory?: string
/**
+ * Only return root sessions (no parentID)
+ */
+ roots?: boolean
+ /**
* Filter sessions updated on or after this timestamp (milliseconds since epoch)
*/
start?: number