Fix pinned host and inbox placement

This commit is contained in:
Brennan Benson
2026-07-16 20:28:39 -07:00
parent d8c165f90c
commit ed5fabb249
4 changed files with 92 additions and 7 deletions
@@ -403,6 +403,47 @@ describe('addHostSectionRows', () => {
])
})
it('keeps a pinned row with its explicit worktree host', () => {
const local = repo('local')
const pinned = pinnedItem('ssh-pinned', local, PINNED_GROUP_KEY)
pinned.worktree.hostId = 'ssh:ssh-1'
const rows = [
pinnedHeader(new Map([['ssh:ssh-1', 1]]), new Map([['ssh:ssh-1', ['ssh-pinned']]])),
pinned,
repoHeader(local),
item('local-wt', local)
]
const sectioned = addHostSectionRows({
rows,
hostOptions: [
{
id: 'local',
kind: 'local',
label: 'Local Mac',
detail: 'This computer',
health: 'local'
},
{ id: 'ssh:ssh-1', kind: 'ssh', label: 'Builder', detail: 'SSH', health: 'available' }
],
workspaceHostScope: 'all',
defaultHostId: 'local'
})
expect(sectioned.map(rowKey)).toEqual([
'host:local',
'repo:local',
'local-wt',
'host:ssh:ssh-1',
PINNED_GROUP_KEY,
'ssh-pinned'
])
expect(sectioned.filter((row) => row.type === 'host-header')).toMatchObject([
{ hostId: 'local', count: 1 },
{ hostId: 'ssh:ssh-1', count: 1 }
])
})
it('does not double-count a collapsed pinned header and its natural duplicate row', () => {
const local = repo('local')
const ssh = repo('ssh', 'ssh-1')
@@ -69,7 +69,9 @@ function getFolderWorkspaceHostId(
function getRowHostId(row: Row, defaultHostId: ExecutionHostId): ExecutionHostId | null {
switch (row.type) {
case 'item':
return getRepoHostId(row.repo, defaultHostId)
// Why: runtime and SSH snapshots can carry a more precise owner than the
// repo fallback; header localization already uses this worktree identity.
return row.worktree.hostId ?? getRepoHostId(row.repo, defaultHostId)
case 'pending-creation':
case 'imported-worktrees-card':
case 'new-external-worktrees-inbox':
@@ -1569,6 +1569,51 @@ describe('buildRows with pinned worktrees', () => {
])
})
it('keeps the inbox group when the repo only has a pinned worktree', () => {
const pinnedWorktree = { ...worktree, id: 'wt-pinned', isPinned: true }
const rows = buildRows(
'repo',
[pinnedWorktree],
repoMap,
null,
new Set(),
undefined,
undefined,
undefined,
{},
new Map([[pinnedWorktree.id, pinnedWorktree]]),
false,
undefined,
[],
new Set(),
new Map(),
new Map([[repo.id, { repo, inboxWorktrees: [makeDetectedWorktree()] }]])
)
expect(rows).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: 'item',
sectionKey: PINNED_GROUP_KEY,
worktree: expect.objectContaining({ id: pinnedWorktree.id })
}),
expect.objectContaining({ type: 'header', key: `repo:${repo.id}` }),
expect.objectContaining({
type: 'new-external-worktrees-inbox',
key: `new-external-worktrees-inbox:${repo.id}`
})
])
)
expect(
rows.some(
(row) =>
row.type === 'item' &&
row.sectionKey === `repo:${repo.id}` &&
row.worktree.id === pinnedWorktree.id
)
).toBe(false)
})
it('does not emit new external worktrees inbox rows outside repo grouping', () => {
const rows = buildRows(
'workspace-status',
@@ -1043,11 +1043,6 @@ export function buildRows(
settings,
projectGrouping
})
// Repos whose only visible worktrees are pinned are surfaced via the pinned
// section, so the repo-grouped inbox loop below must not re-create a group for them.
const visiblePinnedRepoIds = new Set(
worktrees.filter((worktree) => worktree.isPinned).map((worktree) => worktree.repoId)
)
emitPinnedGroup(
worktrees,
repoMap,
@@ -1151,7 +1146,9 @@ export function buildRows(
for (const [repoId, candidate] of newExternalWorktreesInboxByRepo) {
const grouping = getProjectGroupingForRepo(repoId, repoMap, projectIndex)
const key = grouping.key
if (!grouped.has(key) && !visiblePinnedRepoIds.has(repoId)) {
if (!grouped.has(key)) {
// Why: the default policy removes pinned worktrees from natural groups,
// but actionable inbox rows still need a project section to render in.
grouped.set(key, {
label: grouping.label,
items: [],