fix(app): navigate to last session on project nav
This commit is contained in:
@@ -61,6 +61,7 @@ import {
|
|||||||
displayName,
|
displayName,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
getDraggableId,
|
getDraggableId,
|
||||||
|
projectSessionTarget,
|
||||||
sortedRootSessions,
|
sortedRootSessions,
|
||||||
syncWorkspaceOrder,
|
syncWorkspaceOrder,
|
||||||
workspaceKey,
|
workspaceKey,
|
||||||
@@ -82,6 +83,7 @@ export default function Layout(props: ParentProps) {
|
|||||||
Persist.global("layout.page", ["layout.page.v1"]),
|
Persist.global("layout.page", ["layout.page.v1"]),
|
||||||
createStore({
|
createStore({
|
||||||
lastSession: {} as { [directory: string]: string },
|
lastSession: {} as { [directory: string]: string },
|
||||||
|
lastSessionAt: {} as { [directory: string]: number },
|
||||||
activeProject: undefined as string | undefined,
|
activeProject: undefined as string | undefined,
|
||||||
activeWorkspace: undefined as string | undefined,
|
activeWorkspace: undefined as string | undefined,
|
||||||
workspaceOrder: {} as Record<string, string[]>,
|
workspaceOrder: {} as Record<string, string[]>,
|
||||||
@@ -1077,8 +1079,16 @@ export default function Layout(props: ParentProps) {
|
|||||||
function navigateToProject(directory: string | undefined) {
|
function navigateToProject(directory: string | undefined) {
|
||||||
if (!directory) return
|
if (!directory) return
|
||||||
server.projects.touch(directory)
|
server.projects.touch(directory)
|
||||||
const lastSession = store.lastSession[directory]
|
const project = layout.projects
|
||||||
navigateWithSidebarReset(`/${base64Encode(directory)}${lastSession ? `/session/${lastSession}` : ""}`)
|
.list()
|
||||||
|
.find((item) => item.worktree === directory || item.sandboxes?.includes(directory))
|
||||||
|
const target = projectSessionTarget({
|
||||||
|
directory,
|
||||||
|
project,
|
||||||
|
lastSession: store.lastSession,
|
||||||
|
lastSessionAt: store.lastSessionAt,
|
||||||
|
})
|
||||||
|
navigateWithSidebarReset(`/${base64Encode(target.directory)}${target.id ? `/session/${target.id}` : ""}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateToSession(session: Session | undefined) {
|
function navigateToSession(session: Session | undefined) {
|
||||||
@@ -1433,6 +1443,7 @@ export default function Layout(props: ParentProps) {
|
|||||||
const directory = decode64(dir)
|
const directory = decode64(dir)
|
||||||
if (!directory) return
|
if (!directory) return
|
||||||
setStore("lastSession", directory, id)
|
setStore("lastSession", directory, id)
|
||||||
|
setStore("lastSessionAt", directory, Date.now())
|
||||||
notification.session.markViewed(id)
|
notification.session.markViewed(id)
|
||||||
const expanded = untrack(() => store.workspaceExpanded[directory])
|
const expanded = untrack(() => store.workspaceExpanded[directory])
|
||||||
if (expanded === false) {
|
if (expanded === false) {
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { collectOpenProjectDeepLinks, drainPendingDeepLinks, parseDeepLink } from "./deep-links"
|
import { collectOpenProjectDeepLinks, drainPendingDeepLinks, parseDeepLink } from "./deep-links"
|
||||||
import { displayName, errorMessage, getDraggableId, syncWorkspaceOrder, workspaceKey } from "./helpers"
|
import {
|
||||||
|
displayName,
|
||||||
|
errorMessage,
|
||||||
|
getDraggableId,
|
||||||
|
projectSessionTarget,
|
||||||
|
syncWorkspaceOrder,
|
||||||
|
workspaceKey,
|
||||||
|
} from "./helpers"
|
||||||
|
|
||||||
describe("layout deep links", () => {
|
describe("layout deep links", () => {
|
||||||
test("parses open-project deep links", () => {
|
test("parses open-project deep links", () => {
|
||||||
@@ -89,4 +96,34 @@ describe("layout workspace helpers", () => {
|
|||||||
expect(errorMessage(new Error("broken"), "fallback")).toBe("broken")
|
expect(errorMessage(new Error("broken"), "fallback")).toBe("broken")
|
||||||
expect(errorMessage("unknown", "fallback")).toBe("fallback")
|
expect(errorMessage("unknown", "fallback")).toBe("fallback")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("picks newest session across project workspaces", () => {
|
||||||
|
const result = projectSessionTarget({
|
||||||
|
directory: "/root",
|
||||||
|
project: { worktree: "/root", sandboxes: ["/root/a", "/root/b"] },
|
||||||
|
lastSession: {
|
||||||
|
"/root": "root-session",
|
||||||
|
"/root/a": "sandbox-a",
|
||||||
|
"/root/b": "sandbox-b",
|
||||||
|
},
|
||||||
|
lastSessionAt: {
|
||||||
|
"/root": 1,
|
||||||
|
"/root/a": 3,
|
||||||
|
"/root/b": 2,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).toEqual({ directory: "/root/a", id: "sandbox-a", at: 3 })
|
||||||
|
})
|
||||||
|
|
||||||
|
test("falls back to project route when no session exists", () => {
|
||||||
|
const result = projectSessionTarget({
|
||||||
|
directory: "/root",
|
||||||
|
project: { worktree: "/root", sandboxes: ["/root/a"] },
|
||||||
|
lastSession: {},
|
||||||
|
lastSessionAt: {},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).toEqual({ directory: "/root" })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -62,6 +62,24 @@ export const errorMessage = (err: unknown, fallback: string) => {
|
|||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function projectSessionTarget(input: {
|
||||||
|
directory: string
|
||||||
|
project?: { worktree: string; sandboxes?: string[] }
|
||||||
|
lastSession: Record<string, string>
|
||||||
|
lastSessionAt: Record<string, number>
|
||||||
|
}): { directory: string; id?: string; at?: number } {
|
||||||
|
const dirs = input.project ? [input.project.worktree, ...(input.project.sandboxes ?? [])] : [input.directory]
|
||||||
|
const best = dirs.reduce<{ directory: string; id: string; at: number } | undefined>((result, directory) => {
|
||||||
|
const id = input.lastSession[directory]
|
||||||
|
if (!id) return result
|
||||||
|
const at = input.lastSessionAt[directory] ?? 0
|
||||||
|
if (result && result.at >= at) return result
|
||||||
|
return { directory, id, at }
|
||||||
|
}, undefined)
|
||||||
|
if (best) return best
|
||||||
|
return { directory: input.directory }
|
||||||
|
}
|
||||||
|
|
||||||
export const syncWorkspaceOrder = (local: string, dirs: string[], existing?: string[]) => {
|
export const syncWorkspaceOrder = (local: string, dirs: string[], existing?: string[]) => {
|
||||||
if (!existing) return dirs
|
if (!existing) return dirs
|
||||||
const keep = existing.filter((d) => d !== local && dirs.includes(d))
|
const keep = existing.filter((d) => d !== local && dirs.includes(d))
|
||||||
|
|||||||
Reference in New Issue
Block a user