fix(app): sort sessions by persisted time (#41000)

Co-authored-by: Dax <mail@thdxr.com>
This commit is contained in:
opencode-agent[bot] 2026-08-07 04:23:04 +00:00 committed by GitHub
parent 8bf5062b89
commit 28bcc0e4f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 17 deletions

View file

@ -15,7 +15,7 @@ import type { LocalProject } from "@/context/layout"
import { useLanguage } from "@/context/language"
import { ServerConnection } from "@/context/server"
import { sessionHasOpenTab, useTabs } from "@/context/tabs"
import { displayName, errorMessage, projectForSession } from "@/pages/layout/helpers"
import { compareSessionTime, displayName, errorMessage, projectForSession } from "@/pages/layout/helpers"
import { useSessionTabAvatarState } from "@/pages/layout/project-avatar-state"
import { pathKey } from "@/utils/path-key"
import { showToast } from "@/utils/toast"
@ -254,7 +254,7 @@ function buildHomeSessionRecords(input: {
const directories = new Set(input.projectDirectories().map(pathKey))
const sessions = input.sessions().filter((session) => directories.has(pathKey(session.directory)))
return [...new Map(sessions.map((session) => [session.id, session] as const)).values()]
.sort((a, b) => (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created))
.sort(compareSessionTime)
.flatMap((session) => {
const directory = pathKey(session.directory)
const project =

View file

@ -10,6 +10,7 @@ import { type Session } from "@opencode-ai/sdk/v2/client"
import {
childSessionOnPath,
closeHomeProject,
compareSessionTime,
displayName,
effectiveWorkspaceOrder,
errorMessage,
@ -18,6 +19,7 @@ import {
homeProjectDirectories,
homeSessionServerStatus,
latestRootSession,
sortedRootSessions,
toggleHomeProjectSelection,
} from "./helpers"
import { pathKey } from "@/utils/path-key"
@ -153,6 +155,30 @@ describe("layout workspace helpers", () => {
expect(result?.id).toBe("workspace")
})
test("sorts recent sessions by persisted update time instead of id", () => {
const result = sortedRootSessions(
{
path: { directory: "/workspace" },
session: [
session({ id: "ses_z", directory: "/workspace", time: { created: 1, updated: 2, archived: undefined } }),
session({ id: "ses_a", directory: "/workspace", time: { created: 1, updated: 3, archived: undefined } }),
],
},
3,
)
expect(result.map((item) => item.id)).toEqual(["ses_a", "ses_z"])
})
test("uses id only to break equal session timestamps", () => {
const sessions = [
session({ id: "ses_z", directory: "/workspace", time: { created: 1, updated: 2, archived: undefined } }),
session({ id: "ses_a", directory: "/workspace", time: { created: 1, updated: 2, archived: undefined } }),
]
expect(sessions.sort(compareSessionTime).map((item) => item.id)).toEqual(["ses_a", "ses_z"])
})
test("detects project permissions with a filter", () => {
const result = hasProjectPermissions(
{

View file

@ -9,18 +9,10 @@ type SessionStore = {
path: { directory: string }
}
function sortSessions(now: number) {
const oneMinuteAgo = now - 60 * 1000
return (a: Session, b: Session) => {
const aUpdated = a.time.updated ?? a.time.created
const bUpdated = b.time.updated ?? b.time.created
const aRecent = aUpdated > oneMinuteAgo
const bRecent = bUpdated > oneMinuteAgo
if (aRecent && bRecent) return a.id < b.id ? -1 : a.id > b.id ? 1 : 0
if (aRecent && !bRecent) return -1
if (!aRecent && bRecent) return 1
return bUpdated - aUpdated
}
export function compareSessionTime(a: Session, b: Session) {
const updated = (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created)
if (updated !== 0) return updated
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0
}
const isRootVisibleSession = (session: Session, directory: string) =>
@ -29,10 +21,10 @@ const isRootVisibleSession = (session: Session, directory: string) =>
export const roots = (store: SessionStore) =>
(store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
export const sortedRootSessions = (store: SessionStore, now: number) => roots(store).sort(sortSessions(now))
export const sortedRootSessions = (store: SessionStore, _now: number) => roots(store).sort(compareSessionTime)
export const latestRootSession = (stores: SessionStore[], now: number) =>
stores.flatMap(roots).sort(sortSessions(now))[0]
export const latestRootSession = (stores: SessionStore[], _now: number) =>
stores.flatMap(roots).sort(compareSessionTime)[0]
export function hasProjectPermissions<T>(
request: Record<string, T[] | undefined> | undefined,