diff --git a/web/src/components/SessionList.directory-action.test.tsx b/web/src/components/SessionList.directory-action.test.tsx index 3404f27c..1a2f7e16 100644 --- a/web/src/components/SessionList.directory-action.test.tsx +++ b/web/src/components/SessionList.directory-action.test.tsx @@ -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() }) diff --git a/web/src/components/SessionList.tsx b/web/src/components/SessionList.tsx index c3849d0b..dd159d93 100644 --- a/web/src/components/SessionList.tsx +++ b/web/src/components/SessionList.tsx @@ -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>( () => new Map() ) @@ -1821,8 +1811,6 @@ export function SessionList(props: { ) : null} - {pinnedProjectGroups.map(renderDirectoryGroup)} - {runningSessionTotal > 0 ? (
) : null} - {otherProjectGroups.map(renderDirectoryGroup)} + {groups.map(renderDirectoryGroup)}
diff --git a/web/src/lib/locales/en.ts b/web/src/lib/locales/en.ts index a8eb8206..bd22c1df 100644 --- a/web/src/lib/locales/en.ts +++ b/web/src/lib/locales/en.ts @@ -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', diff --git a/web/src/lib/locales/zh-CN.ts b/web/src/lib/locales/zh-CN.ts index 8e76f300..395e0ec7 100644 --- a/web/src/lib/locales/zh-CN.ts +++ b/web/src/lib/locales/zh-CN.ts @@ -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': '详细',