fix(desktop): anchor project trunk + at first repo root when primary path unset
Clicking the project-group trunk + passed the null wire path through, which downstream treats as the reserved Home/detached signal, silently creating a global session. Fall back to the first repo root for path-less explicit projects; Home keeps null. Covers click and new-session drag cwd.
This commit is contained in:
@@ -180,4 +180,26 @@ describe('ProjectOverviewRow', () => {
|
||||
|
||||
expect(onNewSession).toHaveBeenCalledWith(null)
|
||||
})
|
||||
|
||||
// #124808: a real project whose primary_path was never set (multi-folder /
|
||||
// path-less explicit project) still carries repo roots. Its trunk "+" must
|
||||
// anchor the new session at the first repo root, not pass the null wire
|
||||
// path through — null is the reserved Home/detached signal downstream, so
|
||||
// the click silently created a global detached session.
|
||||
it('anchors the trunk "+" at the first repo root when the project has no primary path', () => {
|
||||
const multi = {
|
||||
id: 'p_multi',
|
||||
label: 'Multi',
|
||||
path: null,
|
||||
repos: [{ id: 'r1', label: 'app', path: '/work/app', groups: [], sessionCount: 0 }],
|
||||
sessionCount: 0
|
||||
} as unknown as SidebarProjectTree
|
||||
|
||||
const onNewSession = vi.fn()
|
||||
|
||||
render(<ProjectOverviewRow onNewSession={onNewSession} project={multi} />)
|
||||
fireEvent.click(screen.getByRole('button', { name: 'New session in Multi' }))
|
||||
|
||||
expect(onNewSession).toHaveBeenCalledWith('/work/app')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -147,6 +147,16 @@ export function ProjectOverviewRow({
|
||||
const hiddenCount = total - preview.length
|
||||
const offerShowAll = !showAllSessions && !expanded && preview.length > 0 && hiddenCount > 0
|
||||
|
||||
// #124808: a path-less explicit project (multi-folder, never assigned a
|
||||
// primary_path) still carries repo roots. Its trunk "+" must anchor at
|
||||
// the first repo root — passing the null wire path through would take the
|
||||
// reserved Home/detached branch downstream and silently create a global
|
||||
// session. Home itself keeps null ("no folder" is its contract).
|
||||
const newSessionPath =
|
||||
!project.isNoProject && !(project.path ?? '').trim()
|
||||
? ((project.repos ?? []).map(repo => repo.path).find(root => (root ?? '').trim()) ?? project.path)
|
||||
: project.path
|
||||
|
||||
const showAll = () => {
|
||||
// All-profiles view has no single backend to ask for one project's lanes;
|
||||
// drilling in is the reach there.
|
||||
@@ -204,7 +214,7 @@ export function ProjectOverviewRow({
|
||||
{onNewSession && (
|
||||
<WorkspaceAddButton
|
||||
label={s.newSessionIn(project.label)}
|
||||
onClick={() => onNewSession(project.path)}
|
||||
onClick={() => onNewSession(newSessionPath)}
|
||||
onPointerDown={
|
||||
onNewSessionSplit
|
||||
? event => {
|
||||
@@ -217,11 +227,11 @@ export function ProjectOverviewRow({
|
||||
onNewSessionSplit(placement.dir, {
|
||||
anchor: placement.anchor,
|
||||
before: placement.before,
|
||||
cwd: project.path
|
||||
cwd: newSessionPath
|
||||
})
|
||||
},
|
||||
event,
|
||||
{ cwd: project.path, label: s.newSessionIn(project.label) }
|
||||
{ cwd: newSessionPath, label: s.newSessionIn(project.label) }
|
||||
)
|
||||
}
|
||||
: undefined
|
||||
|
||||
Reference in New Issue
Block a user