app: fix workspace flicker when switching directories (#18207)
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
This commit is contained in:
co-authored by
Shoubhit Dash
parent
cbf4b68fee
commit
84f60d97a0
@@ -104,14 +104,14 @@ 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(workspaceKey("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(workspaceKey("C://")).toBe("C:/")
|
||||
expect(workspaceKey("C:///")).toBe("C:/")
|
||||
})
|
||||
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import { getFilename } from "@opencode-ai/util/path"
|
||||
import { type Session } from "@opencode-ai/sdk/v2/client"
|
||||
|
||||
type SessionStore = {
|
||||
session?: Session[]
|
||||
path: { directory: string }
|
||||
}
|
||||
|
||||
export const workspaceKey = (directory: string) => {
|
||||
const drive = directory.match(/^([A-Za-z]:)[\\/]+$/)
|
||||
if (drive) return `${drive[1]}${directory.includes("\\") ? "\\" : "/"}`
|
||||
if (/^[\\/]+$/.test(directory)) return directory.includes("\\") ? "\\" : "/"
|
||||
return directory.replace(/[\\/]+$/, "")
|
||||
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) {
|
||||
@@ -25,13 +31,11 @@ function sortSessions(now: number) {
|
||||
const isRootVisibleSession = (session: Session, directory: string) =>
|
||||
workspaceKey(session.directory) === workspaceKey(directory) && !session.parentID && !session.time?.archived
|
||||
|
||||
export const sortedRootSessions = (store: { session: Session[]; path: { directory: string } }, now: number) =>
|
||||
store.session.filter((session) => isRootVisibleSession(session, store.path.directory)).sort(sortSessions(now))
|
||||
const roots = (store: SessionStore) => (store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
|
||||
|
||||
export const latestRootSession = (stores: { session: Session[]; path: { directory: string } }[], now: number) =>
|
||||
stores
|
||||
.flatMap((store) => store.session.filter((session) => isRootVisibleSession(session, store.path.directory)))
|
||||
.sort(sortSessions(now))[0]
|
||||
export const sortedRootSessions = (store: SessionStore, now: number) => roots(store).sort(sortSessions(now))
|
||||
|
||||
export const latestRootSession = (stores: SessionStore[], now: number) => stores.flatMap(roots).sort(sortSessions(now))[0]
|
||||
|
||||
export function hasProjectPermissions<T>(
|
||||
request: Record<string, T[] | undefined>,
|
||||
@@ -40,9 +44,9 @@ export function hasProjectPermissions<T>(
|
||||
return Object.values(request).some((list) => list?.some(include))
|
||||
}
|
||||
|
||||
export const childMapByParent = (sessions: Session[]) => {
|
||||
export const childMapByParent = (sessions: Session[] | undefined) => {
|
||||
const map = new Map<string, string[]>()
|
||||
for (const session of sessions) {
|
||||
for (const session of sessions ?? []) {
|
||||
if (!session.parentID) continue
|
||||
const existing = map.get(session.parentID)
|
||||
if (existing) {
|
||||
|
||||
@@ -332,12 +332,13 @@ export const SortableWorkspace = (props: {
|
||||
const open = createMemo(() => props.ctx.workspaceExpanded(props.directory, local()))
|
||||
const boot = createMemo(() => open() || active())
|
||||
const booted = createMemo((prev) => prev || workspaceStore.status === "complete", false)
|
||||
const hasMore = createMemo(() => workspaceStore.sessionTotal > sessions().length)
|
||||
const count = createMemo(() => sessions()?.length ?? 0)
|
||||
const hasMore = createMemo(() => workspaceStore.sessionTotal > count())
|
||||
const busy = createMemo(() => props.ctx.isBusy(props.directory))
|
||||
const wasBusy = createMemo((prev) => prev || busy(), false)
|
||||
const loading = createMemo(() => open() && !booted() && sessions().length === 0 && !wasBusy())
|
||||
const loading = createMemo(() => open() && !booted() && count() === 0 && !wasBusy())
|
||||
const touch = createMediaQuery("(hover: none)")
|
||||
const showNew = createMemo(() => !loading() && (touch() || sessions().length === 0 || (active() && !params.id)))
|
||||
const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id)))
|
||||
const loadMore = async () => {
|
||||
setWorkspaceStore("limit", (limit) => (limit ?? 0) + 5)
|
||||
await globalSync.project.loadSessions(props.directory)
|
||||
@@ -472,8 +473,9 @@ export const LocalWorkspace = (props: {
|
||||
const sessions = createMemo(() => sortedRootSessions(workspace().store, props.sortNow()))
|
||||
const children = createMemo(() => childMapByParent(workspace().store.session))
|
||||
const booted = createMemo((prev) => prev || workspace().store.status === "complete", false)
|
||||
const loading = createMemo(() => !booted() && sessions().length === 0)
|
||||
const hasMore = createMemo(() => workspace().store.sessionTotal > sessions().length)
|
||||
const count = createMemo(() => sessions()?.length ?? 0)
|
||||
const loading = createMemo(() => !booted() && count() === 0)
|
||||
const hasMore = createMemo(() => workspace().store.sessionTotal > count())
|
||||
const loadMore = async () => {
|
||||
workspace().setStore("limit", (limit) => (limit ?? 0) + 5)
|
||||
await globalSync.project.loadSessions(props.project.worktree)
|
||||
|
||||
Reference in New Issue
Block a user