fix(web): keep project pin inside groups below In progress (#1458)

* fix(web): keep project pin inside groups below In progress

Revert #1432's section lift: Pin in project stays first inside its
folder and among directory groups, but must not promote whole folders
above In progress. Restore Settings copy to match.

Fixes #1457

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): align pin-in-progress Settings copy with exclusions

Describe unpinned floaters only, keep global pins above In progress,
and avoid implying every working session or project-pin folders float.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
HeavyGee
2026-08-09 12:45:01 +01:00
committed by GitHub
co-authored by Cursor
parent 00b6e44869
commit b8a765d4ef
4 changed files with 20 additions and 22 deletions
@@ -496,7 +496,7 @@ describe('SessionList collapse behavior', () => {
expect(screen.getByRole('button', { name: /Pinned running task/ })).toBeInTheDocument()
})
it('renders project-pin groups above In progress when pin-in-progress is on', () => {
it('keeps In progress above project-pin groups; project pin stays first inside its group', () => {
localStorage.setItem('hapi-pin-in-progress-sessions', 'true')
const sessions = [
makeSession({
@@ -508,9 +508,14 @@ describe('SessionList collapse behavior', () => {
makeSession({
id: 'session-project-pin',
pinned: true,
updatedAt: 200,
updatedAt: 100,
metadata: { path: '/work/pinned-project', name: 'Project pin', flavor: 'codex' },
}),
makeSession({
id: 'session-project-idle',
updatedAt: 200,
metadata: { path: '/work/pinned-project', name: 'Project idle', flavor: 'codex' },
}),
makeSession({
id: 'session-floater',
active: true,
@@ -527,14 +532,19 @@ describe('SessionList collapse behavior', () => {
render(renderSessionList(sessions, null))
const globalSection = screen.getByTitle('Pinned sessions')
const projectPinGroup = screen.getByTitle('/work/pinned-project')
const inProgress = screen.getByTitle('In progress')
const projectPinGroup = screen.getByTitle('/work/pinned-project')
const otherGroup = screen.getByTitle('/work/other')
const projectPinRow = screen.getByRole('button', { name: /Project pin/ })
const projectIdleRow = screen.getByRole('button', { name: /Project idle/ })
expect(globalSection).toAppearBefore(projectPinGroup)
expect(projectPinGroup).toAppearBefore(inProgress)
expect(inProgress).toAppearBefore(otherGroup)
expect(screen.getByRole('button', { name: /Project pin/ })).toBeInTheDocument()
// Section order: global pin band → In progress → directory groups
// (project-pin groups may sort first among groups, but never above In progress).
expect(globalSection).toAppearBefore(inProgress)
expect(inProgress).toAppearBefore(projectPinGroup)
expect(projectPinGroup).toAppearBefore(otherGroup)
// Intra-group: project pin stays first inside its folder.
expect(projectPinRow).toAppearBefore(projectIdleRow)
expect(screen.getByRole('button', { name: /Unpinned floater/ })).toBeInTheDocument()
})
+1 -13
View File
@@ -1283,16 +1283,6 @@ export function SessionList(props: {
),
[machineFilteredSessions, pinInProgressSessions]
)
// Durable project pins beat ephemeral In progress floaters: pin-containing
// groups render above the running section; unpinned groups stay below.
const pinnedProjectGroups = useMemo(
() => groups.filter((group) => group.hasPinnedSession),
[groups]
)
const otherProjectGroups = useMemo(
() => groups.filter((group) => !group.hasPinnedSession),
[groups]
)
const [collapseOverrides, setCollapseOverrides] = useState<Map<string, boolean>>(
() => new Map()
)
@@ -1821,8 +1811,6 @@ export function SessionList(props: {
</div>
) : null}
{pinnedProjectGroups.map(renderDirectoryGroup)}
{runningSessionTotal > 0 ? (
<div key="running-section">
<div
@@ -1886,7 +1874,7 @@ export function SessionList(props: {
</div>
</div>
) : null}
{otherProjectGroups.map(renderDirectoryGroup)}
{groups.map(renderDirectoryGroup)}
</div>
</div>
</div>
+1 -1
View File
@@ -791,7 +791,7 @@ export default {
'settings.display.activeSessionsOnly': 'Active sessions only',
'settings.display.activeSessionsOnly.desc': 'Hide inactive sessions in the sidebar. The session you have open stays visible.',
'settings.display.pinInProgressSessions': 'Pin in-progress sessions',
'settings.display.pinInProgressSessions.desc': 'Move unpinned working and pending sessions into an In progress section. Global pins and projects with a project pin stay above that section; quiet actives stay in their project directories. Off keeps everything in directory groups.',
'settings.display.pinInProgressSessions.desc': 'Move unpinned working and pending sessions into an In progress section above project folders. Global pins remain above it; quiet active sessions stay inside their project folders. Off keeps everything in directory groups.',
'settings.display.sessionListStatus': 'Session list status',
'settings.display.sessionListStatus.standard': 'Standard',
'settings.display.sessionListStatus.detailed': 'Detailed',
+1 -1
View File
@@ -790,7 +790,7 @@ export default {
'settings.display.activeSessionsOnly': '仅显示活跃会话',
'settings.display.activeSessionsOnly.desc': '在侧边栏隐藏非活跃会话;当前打开的会话仍会保留显示。',
'settings.display.pinInProgressSessions': '置顶进行中会话',
'settings.display.pinInProgressSessions.desc': '将未置顶的运行中和待处理会话移到「进行中」分区。全局置顶以及含项目置顶的项目分组仍在该分区之上;安静的活跃会话留在各自项目目录分组中。关闭后全部保留在目录分组中。',
'settings.display.pinInProgressSessions.desc': '将未置顶的运行中和待处理会话移到「进行中」分区(位于项目目录分组之上)。全局置顶仍在该分区之上;安静的活跃会话留在各自项目目录分组中。关闭后全部保留在目录分组中。',
'settings.display.sessionListStatus': '会话列表状态',
'settings.display.sessionListStatus.standard': '标准',
'settings.display.sessionListStatus.detailed': '详细',