fix(desktop): show repo-root-only sessions in project drill-in (#94552)
This commit is contained in:
@@ -629,6 +629,60 @@ describe('overlayLiveLanes', () => {
|
||||
expect(overlaid.sessionCount).toBe(1)
|
||||
})
|
||||
|
||||
it('keeps cwd-less repo sessions visible in both the overview and project drill-in', () => {
|
||||
const project = projectNode({
|
||||
id: '/www/app',
|
||||
isAuto: true,
|
||||
repos: [
|
||||
{
|
||||
id: '/www/app',
|
||||
label: 'app',
|
||||
path: '/www/app',
|
||||
sessionCount: 0,
|
||||
groups: [lane({ id: '/www/app::branch::main', label: 'main', isMain: true, path: '/www/app' })]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const live = makeCwdSession(null, { id: 'fresh', git_branch: 'main', git_repo_root: '/www/app' })
|
||||
|
||||
expect(overlayLivePreviews([project], [live], [], 3)['/www/app'].map(session => session.id)).toEqual(['fresh'])
|
||||
|
||||
const overlaid = overlayLiveLanes(project, [live])
|
||||
|
||||
expect(overlaid.repos[0].groups.flatMap(group => group.sessions.map(session => session.id))).toEqual(['fresh'])
|
||||
expect(overlaid.sessionCount).toBe(1)
|
||||
})
|
||||
|
||||
it('places a cwd-less repo session only in its exact repo subtree', () => {
|
||||
const project = projectNode({
|
||||
id: '/www',
|
||||
repos: [
|
||||
{
|
||||
id: '/www',
|
||||
label: 'www',
|
||||
path: '/www',
|
||||
sessionCount: 0,
|
||||
groups: [lane({ id: '/www::branch::main', label: 'main', isMain: true, path: '/www' })]
|
||||
},
|
||||
{
|
||||
id: '/www/app',
|
||||
label: 'app',
|
||||
path: '/www/app',
|
||||
sessionCount: 0,
|
||||
groups: [lane({ id: '/www/app::branch::main', label: 'main', isMain: true, path: '/www/app' })]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const live = makeCwdSession(null, { id: 'fresh', git_branch: 'main', git_repo_root: '/www/app' })
|
||||
const overlaid = overlayLiveLanes(project, [live])
|
||||
|
||||
expect(overlaid.repos[0].groups.flatMap(group => group.sessions)).toEqual([])
|
||||
expect(overlaid.repos[1].groups.flatMap(group => group.sessions.map(session => session.id))).toEqual(['fresh'])
|
||||
expect(overlaid.sessionCount).toBe(1)
|
||||
})
|
||||
|
||||
it('injects a session created in a fresh worktree into that worktree lane (no git_repo_root yet)', () => {
|
||||
// The brand-new session row has only a cwd — no git_repo_root. The entered
|
||||
// project knows its repo root, so the worktree session still lands in its
|
||||
|
||||
@@ -451,21 +451,34 @@ export function sessionProjectColor(session: SessionInfo, projects: ProjectInfo[
|
||||
const upsertSession = (rows: SessionInfo[], session: SessionInfo): SessionInfo[] =>
|
||||
[session, ...rows.filter(row => row.id !== session.id)].sort((a, b) => sessionRecency(b) - sessionRecency(a))
|
||||
|
||||
/** A live row's placement path, with an exact repo-root fallback when cwd is absent. */
|
||||
function livePathForRepo(repoRoot: string, session: SessionInfo): string {
|
||||
const cwd = (session.cwd || '').trim()
|
||||
|
||||
if (cwd) {
|
||||
return cwd
|
||||
}
|
||||
|
||||
const persistedRoot = (session.git_repo_root || '').trim()
|
||||
|
||||
return persistedRoot && pathKey(persistedRoot) === pathKey(repoRoot) ? persistedRoot : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* The lane a live session belongs to WITHIN a known repo root, by path — the
|
||||
* entered project already knows its repo roots, so we don't need the session's
|
||||
* (often-unset, on a fresh row) git_repo_root. Mirrors the backend's lane ids:
|
||||
* The lane a live session belongs to WITHIN a known repo root, by path. A fresh
|
||||
* row normally uses cwd; older/imported rows can carry only git_repo_root, which
|
||||
* still identifies the main checkout exactly. Mirrors the backend's lane ids:
|
||||
* main checkout -> branch lane, `.worktrees/t_<hex>` -> kanban, any other
|
||||
* `.worktrees/<slug>` -> that worktree's own lane.
|
||||
*/
|
||||
function liveLaneForRepo(repoRoot: string, session: SessionInfo): null | SidebarSessionGroup {
|
||||
const cwd = (session.cwd || '').trim()
|
||||
const sessionPath = livePathForRepo(repoRoot, session)
|
||||
|
||||
if (!cwd || !isPathUnder(repoRoot, cwd)) {
|
||||
if (!sessionPath || !isPathUnder(repoRoot, sessionPath)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const wt = cwd.match(/^(.*[/\\]\.worktrees)[/\\]([^/\\]+)/)
|
||||
const wt = sessionPath.match(/^(.*[/\\]\.worktrees)[/\\]([^/\\]+)/)
|
||||
|
||||
if (wt) {
|
||||
const [worktreeRoot, worktreesDir, slug] = [wt[0], wt[1], wt[2]]
|
||||
@@ -516,9 +529,9 @@ export function overlayRepoLanes(
|
||||
})
|
||||
|
||||
for (const session of live) {
|
||||
const cwd = (session.cwd || '').trim()
|
||||
const sessionPath = livePathForRepo(repo.path ?? '', session)
|
||||
|
||||
if (removed.has(session.id) || !cwd) {
|
||||
if (removed.has(session.id) || !sessionPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -533,7 +546,7 @@ export function overlayRepoLanes(
|
||||
for (const g of lanes) {
|
||||
const lanePath = normalizePath(g.path)
|
||||
|
||||
if (!lanePath || pathKey(lanePath) === repoRootKey || !isPathUnder(lanePath, cwd)) {
|
||||
if (!lanePath || pathKey(lanePath) === repoRootKey || !isPathUnder(lanePath, sessionPath)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user