fix(desktop): honor effective project profile scope

This commit is contained in:
ehz0ah
2026-09-09 10:36:40 +08:00
committed by brooklyn!
parent 81c2145c8d
commit 32c00d30f8
2 changed files with 38 additions and 4 deletions

View File

@@ -4,7 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { NO_PROJECT_ID, type SidebarProjectTree } from '@/app/chat/sidebar/projects/workspace-groups'
import { $sidebarAgentsGrouped, setSidebarAgentsGrouped } from '@/store/layout'
import { $activeGatewayProfile, $profileScope, ALL_PROFILES, setShowAllProfiles } from '@/store/profile'
import { $activeGatewayProfile, $profiles, $profileScope, ALL_PROFILES, setShowAllProfiles } from '@/store/profile'
import { $currentCwd, $selectedStoredSessionId, $sessions, applyConfiguredDefaultProjectDir } from '@/store/session'
import { deferred } from '@/test/deferred'
import type { ProjectInfo } from '@/types/hermes'
@@ -135,6 +135,7 @@ describe('projects RPC profile forwarding', () => {
beforeEach(() => {
vi.clearAllMocks()
$activeGatewayProfile.set('default')
$profiles.set([{ is_default: true, name: 'default' } as never])
$activeProjectId.set(null)
$projectTree.set([])
setShowAllProfiles(false)
@@ -199,6 +200,7 @@ describe('projects RPC profile forwarding', () => {
const gateway = { connectionState: 'open', request }
activeGateway.mockReturnValue(gateway as never)
gatewayAtom.set(gateway as never)
$profiles.set([{ is_default: true, name: 'default' } as never, { is_default: false, name: 'work' } as never])
setShowAllProfiles(true)
await refreshProjects()
@@ -208,6 +210,32 @@ describe('projects RPC profile forwarding', () => {
expect(request).not.toHaveBeenCalled()
setShowAllProfiles(false)
})
it('uses the active profile when a persisted all-profiles preference is hidden for one profile', async () => {
const project = { id: 'p_123', label: 'P', path: null, repos: [], sessionCount: 0 } as SidebarProjectTree
const request = vi.fn(async (method: string) =>
method === 'projects.project_sessions' ? { project } : { active_id: null, projects: [], scoped_session_ids: [] }
)
const gateway = { connectionState: 'open', request }
activeGateway.mockReturnValue(gateway as never)
gatewayAtom.set(gateway as never)
setShowAllProfiles(true)
await refreshProjects()
await refreshProjectTree()
await expect(fetchProjectSessions('p_123')).resolves.toBe(project)
expect(request).toHaveBeenNthCalledWith(1, 'projects.list', { profile: 'default' })
expect(request).toHaveBeenNthCalledWith(2, 'projects.tree', { preview_limit: 3, profile: 'default' })
expect(request).toHaveBeenNthCalledWith(3, 'projects.project_sessions', {
profile: 'default',
project_id: 'p_123'
})
setShowAllProfiles(false)
})
})
describe('resolveNewSessionCwd', () => {
@@ -425,6 +453,7 @@ describe('createProject', () => {
$projects.set([])
$projectTree.set([])
$activeGatewayProfile.set('default')
$profiles.set([{ is_default: true, name: 'default' } as never, { is_default: false, name: 'work' } as never])
setShowAllProfiles(false)
})

View File

@@ -29,6 +29,7 @@ import { $sidebarShowAllSessions, setSidebarAgentsGrouped } from '@/store/layout
import { notify } from '@/store/notifications'
import {
$activeGatewayProfile,
$profiles,
$profileScope,
ALL_PROFILES,
normalizeProfileKey,
@@ -304,10 +305,14 @@ async function gatewayRequest<T>(method: string, params: Record<string, unknown>
return gateway.request<T>(method, params)
}
function viewingAllProfiles(): boolean {
return $profileScope.get() === ALL_PROFILES && $profiles.get().length > 1
}
export function projectProfile(): null | string {
const profile = normalizeProfileKey($activeGatewayProfile.get())
return $profileScope.get() === ALL_PROFILES || profile === ALL_PROFILES ? null : profile
return viewingAllProfiles() || profile === ALL_PROFILES ? null : profile
}
// All profiles filters the sidebar. Writes still belong to the live gateway profile.
@@ -561,7 +566,7 @@ async function refreshProjectTreeOn(context: ActiveProjectsContext): Promise<voi
// sessions + the scoped-session-id set). Best-effort: a failure leaves the
// cached tree intact so the sidebar doesn't flicker.
export async function refreshProjectTree(): Promise<void> {
if ($profileScope.get() === ALL_PROFILES) {
if (viewingAllProfiles()) {
await refreshProjectTreeAcrossProfiles()
return
@@ -593,7 +598,7 @@ async function refreshProjectTreeAcrossProfiles(): Promise<void> {
// scope; the newer refresh owns the tree.
if (
generation !== projectTreeRefreshGeneration ||
$profileScope.get() !== ALL_PROFILES ||
!viewingAllProfiles() ||
activeGatewayConnectionId() !== owner.connectionId
) {
return