fix(desktop): Path mismatches cause sessions missing + strong ID + existing data fix (#25013)
This commit is contained in:
@@ -14,8 +14,8 @@ import {
|
||||
errorMessage,
|
||||
hasProjectPermissions,
|
||||
latestRootSession,
|
||||
workspaceKey,
|
||||
} from "./helpers"
|
||||
import { pathKey } from "@/utils/path-key"
|
||||
|
||||
const session = (input: Partial<Session> & Pick<Session, "id" | "directory">) =>
|
||||
({
|
||||
@@ -104,16 +104,16 @@ describe("layout deep links", () => {
|
||||
|
||||
describe("layout workspace helpers", () => {
|
||||
test("normalizes trailing slash in workspace key", () => {
|
||||
expect(workspaceKey("/tmp/demo///")).toBe("/tmp/demo")
|
||||
expect(workspaceKey("C:\\tmp\\demo\\\\")).toBe("C:/tmp/demo")
|
||||
expect(String(pathKey("/tmp/demo///"))).toBe("/tmp/demo")
|
||||
expect(String(pathKey("C:\\tmp\\demo\\\\"))).toBe("C:/tmp/demo")
|
||||
})
|
||||
|
||||
test("preserves posix and drive roots in workspace key", () => {
|
||||
expect(workspaceKey("/")).toBe("/")
|
||||
expect(workspaceKey("///")).toBe("/")
|
||||
expect(workspaceKey("C:\\")).toBe("C:/")
|
||||
expect(workspaceKey("C://")).toBe("C:/")
|
||||
expect(workspaceKey("C:///")).toBe("C:/")
|
||||
expect(String(pathKey("/"))).toBe("/")
|
||||
expect(String(pathKey("///"))).toBe("/")
|
||||
expect(String(pathKey("C:\\"))).toBe("C:/")
|
||||
expect(String(pathKey("C://"))).toBe("C:/")
|
||||
expect(String(pathKey("C:///"))).toBe("C:/")
|
||||
})
|
||||
|
||||
test("keeps local first while preserving known order", () => {
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { getFilename } from "@opencode-ai/core/util/path"
|
||||
import { type Session } from "@opencode-ai/sdk/v2/client"
|
||||
import { pathKey } from "@/utils/path-key"
|
||||
|
||||
type SessionStore = {
|
||||
session?: Session[]
|
||||
path: { directory: string }
|
||||
}
|
||||
|
||||
export const workspaceKey = (directory: string) => {
|
||||
const value = directory.replaceAll("\\", "/")
|
||||
const drive = value.match(/^([A-Za-z]:)\/+$/)
|
||||
if (drive) return `${drive[1]}/`
|
||||
if (/^\/+$/i.test(value)) return "/"
|
||||
return value.replace(/\/+$/, "")
|
||||
}
|
||||
|
||||
function sortSessions(now: number) {
|
||||
const oneMinuteAgo = now - 60 * 1000
|
||||
return (a: Session, b: Session) => {
|
||||
@@ -29,7 +22,7 @@ function sortSessions(now: number) {
|
||||
}
|
||||
|
||||
const isRootVisibleSession = (session: Session, directory: string) =>
|
||||
workspaceKey(session.directory) === workspaceKey(directory) && !session.parentID && !session.time?.archived
|
||||
pathKey(session.directory) === pathKey(directory) && !session.parentID && !session.time?.archived
|
||||
|
||||
export const roots = (store: SessionStore) =>
|
||||
(store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
|
||||
@@ -72,11 +65,11 @@ export const errorMessage = (err: unknown, fallback: string) => {
|
||||
}
|
||||
|
||||
export const effectiveWorkspaceOrder = (local: string, dirs: string[], persisted?: string[]) => {
|
||||
const root = workspaceKey(local)
|
||||
const root = pathKey(local)
|
||||
const live = new Map<string, string>()
|
||||
|
||||
for (const dir of dirs) {
|
||||
const key = workspaceKey(dir)
|
||||
const key = pathKey(dir)
|
||||
if (key === root) continue
|
||||
if (!live.has(key)) live.set(key, dir)
|
||||
}
|
||||
@@ -85,7 +78,7 @@ export const effectiveWorkspaceOrder = (local: string, dirs: string[], persisted
|
||||
|
||||
const result = [local]
|
||||
for (const dir of persisted) {
|
||||
const key = workspaceKey(dir)
|
||||
const key = pathKey(dir)
|
||||
if (key === root) continue
|
||||
const match = live.get(key)
|
||||
if (!match) continue
|
||||
|
||||
@@ -16,8 +16,9 @@ import { type Session } from "@opencode-ai/sdk/v2/client"
|
||||
import { type LocalProject } from "@/context/layout"
|
||||
import { loadSessionsQuery, useGlobalSync } from "@/context/global-sync"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { pathKey } from "@/utils/path-key"
|
||||
import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items"
|
||||
import { sortedRootSessions, workspaceKey } from "./helpers"
|
||||
import { sortedRootSessions } from "./helpers"
|
||||
import { useQuery } from "@tanstack/solid-query"
|
||||
|
||||
type InlineEditorComponent = (props: {
|
||||
@@ -309,7 +310,7 @@ export const SortableWorkspace = (props: {
|
||||
const slug = createMemo(() => base64Encode(props.directory))
|
||||
const sessions = createMemo(() => sortedRootSessions(workspaceStore, props.sortNow()))
|
||||
const local = createMemo(() => props.directory === props.project.worktree)
|
||||
const active = createMemo(() => workspaceKey(props.ctx.currentDir()) === workspaceKey(props.directory))
|
||||
const active = createMemo(() => pathKey(props.ctx.currentDir()) === pathKey(props.directory))
|
||||
const workspaceValue = createMemo(() => {
|
||||
const branch = workspaceStore.vcs?.branch
|
||||
const name = branch ?? getFilename(props.directory)
|
||||
|
||||
Reference in New Issue
Block a user