mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-01 22:48:16 +00:00
fix(desktop): "load more" button behavior in desktop sidebar (#8430)
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
39
packages/opencode/test/server/session-list.test.ts
Normal file
39
packages/opencode/test/server/session-list.test.ts
Normal file
@@ -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)
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -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" },
|
||||
|
||||
@@ -2589,7 +2589,14 @@ 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)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user