fix(projects): drop parent folders; attribute sessions to the deepest project
Some checks failed
ios / package-tests (APIClient) (push) Has been cancelled
ios / package-tests (HostRegistry) (push) Has been cancelled
ios / package-tests (SessionCore) (push) Has been cancelled
ios / package-tests (WireProtocol) (push) Has been cancelled
ios / testsupport-tests (push) Has been cancelled
ios / app-tests (push) Has been cancelled
ios / ipad-tests (push) Has been cancelled
ios / integration-tests (push) Has been cancelled
ios / ui-test (push) Has been cancelled
ios / ios17-floor-tests (push) Has been cancelled
relay-tripwire / cross-tenant-tripwire (push) Has been cancelled
Some checks failed
ios / package-tests (APIClient) (push) Has been cancelled
ios / package-tests (HostRegistry) (push) Has been cancelled
ios / package-tests (SessionCore) (push) Has been cancelled
ios / package-tests (WireProtocol) (push) Has been cancelled
ios / testsupport-tests (push) Has been cancelled
ios / app-tests (push) Has been cancelled
ios / ipad-tests (push) Has been cancelled
ios / integration-tests (push) Has been cancelled
ios / ui-test (push) Has been cancelled
ios / ios17-floor-tests (push) Has been cancelled
relay-tripwire / cross-tenant-tripwire (push) Has been cancelled
The projects panel listed bare parent folders (~, ~/Documents) as projects and a single session lit up every ancestor project's 'Active now'. dropParentFolders filters non-git entries that merely contain other listed projects; assignSessions attributes each live session to the DEEPEST containing project (detail page keeps prefix matching). +3 tests; projects 29/29, tsc clean. Frontend unchanged.
This commit is contained in:
@@ -212,6 +212,28 @@ describe('buildProjects — session merge', () => {
|
||||
expect(repoA.sessions.find((s) => s.id === 's-under')!.title).toBe('http')
|
||||
})
|
||||
|
||||
it('attributes a session only to the DEEPEST project containing its cwd', async () => {
|
||||
// repoA is discovered by the scan; the nested repoA/sub repo enters via
|
||||
// history (scan does not descend into repos). A session inside sub must
|
||||
// NOT also light up the ancestor repoA.
|
||||
const repoPath = path.join(tmp, 'repoA')
|
||||
const subPath = path.join(repoPath, 'sub')
|
||||
await makeRepo(repoPath, 'main')
|
||||
await makeRepo(subPath, 'dev')
|
||||
mockListSessions.mockResolvedValue([
|
||||
{ id: 'h1', cwd: subPath, project: 'sub', mtimeMs: 1000, preview: '' },
|
||||
])
|
||||
const cfg = makeCfg({ projectRoots: [tmp], projectScanDepth: 2, projectDirtyCheck: false })
|
||||
|
||||
const live = [makeLive({ id: 's-deep', cwd: path.join(subPath, 'src') })]
|
||||
const out = await buildProjects(cfg, live)
|
||||
|
||||
const repoA = out.find((p) => p.path === repoPath)!
|
||||
const sub = out.find((p) => p.path === subPath)!
|
||||
expect(sub.sessions.map((s) => s.id)).toEqual(['s-deep'])
|
||||
expect(repoA.sessions).toEqual([])
|
||||
})
|
||||
|
||||
it('re-merges live sessions FRESH on every call (discovery is cached)', async () => {
|
||||
await makeRepo(path.join(tmp, 'repoA'), 'main')
|
||||
const repoPath = path.join(tmp, 'repoA')
|
||||
@@ -266,6 +288,36 @@ describe('buildProjects — history merge & sorting', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('drops non-git parent folders that merely contain other projects', async () => {
|
||||
// Running a session in ~/Documents once puts it in history; it must not be
|
||||
// listed as a project when it only contains real repos (parent folder).
|
||||
const repoPath = path.join(tmp, 'repoA')
|
||||
await makeRepo(repoPath, 'main')
|
||||
mockListSessions.mockResolvedValue([
|
||||
{ id: 'h1', cwd: tmp, project: path.basename(tmp), mtimeMs: 2000, preview: '' },
|
||||
{ id: 'h2', cwd: repoPath, project: 'repoA', mtimeMs: 1000, preview: '' },
|
||||
])
|
||||
const cfg = makeCfg({ projectRoots: [tmp], projectScanDepth: 2, projectDirtyCheck: false })
|
||||
|
||||
const out = await buildProjects(cfg, [])
|
||||
|
||||
expect(out.some((p) => p.path === tmp)).toBe(false) // parent folder dropped
|
||||
expect(out.some((p) => p.path === repoPath)).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps a non-git history project that contains no other project', async () => {
|
||||
const standalone = path.join(tmp, 'notes')
|
||||
await fs.mkdir(standalone, { recursive: true })
|
||||
mockListSessions.mockResolvedValue([
|
||||
{ id: 'h1', cwd: standalone, project: 'notes', mtimeMs: 2000, preview: '' },
|
||||
])
|
||||
const cfg = makeCfg({ projectRoots: [tmp], projectScanDepth: 2, projectDirtyCheck: false })
|
||||
|
||||
const out = await buildProjects(cfg, [])
|
||||
|
||||
expect(out.some((p) => p.path === standalone)).toBe(true)
|
||||
})
|
||||
|
||||
it('sorts by lastActiveMs desc, undefined last, name asc tiebreak', async () => {
|
||||
await makeRepo(path.join(tmp, 'zzz'), 'main') // no history -> undefined
|
||||
await makeRepo(path.join(tmp, 'aaa'), 'main') // no history -> undefined
|
||||
|
||||
Reference in New Issue
Block a user