fix(desktop): keep the sidebar alive for messaging-only and cron-only profiles

showSessionSections gated the whole session area — search, sessions,
messaging platforms, cron jobs — on normal-session visibility. A profile
whose only sessions are messaging threads, or that only has scheduled
jobs, collapsed the sidebar to the 'No sessions yet' blank state, hiding
its Telegram/Slack conversations and jobs until a normal session was
created (the messaging half of #63593).

Messaging sessions and cron jobs are already profile-scoped upstream
(sidebarProfileForScope / filterSessionsByProfileScope), so the sections
rendered inside the area are the active profile's own — no state is shared
between profiles.

Fixes #63593
This commit is contained in:
Hermes Agent
2026-09-25 12:33:22 -05:00
committed by brooklyn!
parent ca16be564d
commit 41cd3117ae
2 changed files with 65 additions and 1 deletions

View File

@@ -345,6 +345,61 @@ describe('ChatSidebar section labels', () => {
})
})
describe('ChatSidebar empty-profile sections', () => {
// A profile with no normal sessions but messaging threads / cron jobs must
// still show them: the session area (and the sections inside it) is gated by
// showSessionSections, which used to key only on normal-session visibility
// and collapsed these profiles to the blank state (#63593).
const telegramThread = (id: string, last_active: number) =>
makeSessionInfo({ connection_id: 'local', id, last_active, profile: 'default', source: 'telegram', title: id })
beforeEach(() => {
$connectionsRegistry.set({
version: 2,
primary: 'local',
secureTokenStorage: true,
connections: [{ id: 'local', label: 'This computer', kind: 'local', tokenSet: false, tokenPreview: null }]
} as NonNullable<typeof $connectionsRegistry.value>)
$profiles.set([{ name: 'default', is_default: true }] as typeof $profiles.value)
$sessions.set([])
$messagingSessions.set([telegramThread('tg-one', 60), telegramThread('tg-two', 30)])
$messagingTruncated.set(false)
$sidebarMessagingOpenIds.set(['telegram'])
$sessionsLoading.set(false)
})
afterEach(() => {
cleanup()
$messagingSessions.set([])
$sidebarMessagingOpenIds.set([])
$sessions.set([])
})
it('shows the messaging section for a profile with no normal sessions', () => {
const { container } = renderSidebar('/', 'chat')
// The Telegram platform section renders with its threads…
expect(screen.getAllByText('Telegram').length).toBeGreaterThan(0)
expect(screen.getByText('tg-one')).toBeTruthy()
// …and the sidebar did not collapse to the blank state: the search field
// only renders inside the session area, so its presence proves the area
// (and the messaging sections inside it) rendered.
expect(screen.getByPlaceholderText('Search sessions…')).toBeTruthy()
})
it('still shows the blank state when a profile has nothing at all', () => {
$messagingSessions.set([])
$sidebarMessagingOpenIds.set([])
// SidebarBlankState: a centered "No sessions yet" plus a "New project"
// button, rendered INSTEAD of the whole session area (search included).
const { container } = renderSidebar('/', 'chat')
expect(container.textContent).toContain('No sessions yet')
expect(screen.queryByPlaceholderText('Search sessions…')).toBeNull()
})
})
describe('ChatSidebar messaging owners', () => {
const telegram = (id: string, profile: string, last_active: number) =>
makeSessionInfo({ connection_id: 'local', id, last_active, profile, source: 'telegram', title: id })

View File

@@ -1524,8 +1524,17 @@ export function ChatSidebar({
// Filtered down to nothing still renders the section: the empty state is what
// tells you the filter — not an empty account — is why the list is bare.
// Messaging threads and cron jobs live inside this area too: a profile whose
// only sessions are messaging threads (or that only has scheduled jobs) must
// not collapse the whole sidebar to the blank state (#63593).
const showSessionSections =
showSessionSkeletons || sessionsLoadError || filtersActive || sortedSessions.length > 0 || projectModel.length > 0
showSessionSkeletons ||
sessionsLoadError ||
filtersActive ||
sortedSessions.length > 0 ||
projectModel.length > 0 ||
messagingGroups.length > 0 ||
(showsAdvancedChrome && cronJobs.length > 0)
// The sidebar's session-area mode — exposed as data-attributes so custom
// skins can target project mode (overview vs. entered), archived, or search