Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const mockStartNewSessionDraft = vi.fn()
const mockDeleteConversation = vi.fn()
const mockDeleteAllConversations = vi.fn()
const mockUpdateConversationTitle = vi.fn()
const mockCloseRightPanel = vi.fn()
const mockOpenRightPanel = vi.fn()

// Mock the useSessionUrl hook (uses Next.js App Router hooks)
vi.mock('@/hooks/use-session-url', () => ({
Expand Down Expand Up @@ -54,7 +54,7 @@ vi.mock('../store', () => ({
isSessionsPanelOpen: false,
setSessionsPanelOpen: vi.fn(),
enabledDataSourceIds: ['source-1', 'source-2'],
closeRightPanel: mockCloseRightPanel,
openRightPanel: mockOpenRightPanel,
})),
}))

Expand Down Expand Up @@ -151,7 +151,7 @@ describe('MainLayout', () => {
test('passes auth state to components', () => {
const onSignIn = vi.fn()
const onSignOut = vi.fn()
const user = { name: 'Test User', email: 'test@example.com' }
const user = { name: 'Test User', email: 'test@nvidia.com' }

render(
<MainLayout isAuthenticated={true} user={user} onSignIn={onSignIn} onSignOut={onSignOut} />
Expand All @@ -172,7 +172,7 @@ describe('MainLayout', () => {

expect(mockStartNewSessionDraft).toHaveBeenCalledOnce()
expect(mockClearSessionUrl).toHaveBeenCalledOnce()
expect(mockCloseRightPanel).toHaveBeenCalledOnce()
expect(mockOpenRightPanel).toHaveBeenCalledWith('data-sources')
})

test('disables new session action while shallow streaming is active', () => {
Expand Down
7 changes: 4 additions & 3 deletions frontends/ui/src/features/layout/components/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const MainLayout: FC<MainLayoutProps> = ({
deepResearchOwnerConversationId,
} = useChatStore()

const { rightPanel, closeRightPanel } = useLayoutStore()
const { rightPanel, openRightPanel } = useLayoutStore()
const prefersReducedMotion = useReducedMotion()

// Deep research SSE hook - manages connection when deep research starts
Expand All @@ -93,11 +93,12 @@ export const MainLayout: FC<MainLayoutProps> = ({
)

// Start a new unsaved draft session and clear URL until first interaction.
// Open Data Sources panel so it stays visible (default panel for new sessions).
const handleNewSession = useCallback(() => {
startNewSessionDraft()
clearSessionUrl()
closeRightPanel()
}, [startNewSessionDraft, clearSessionUrl, closeRightPanel])
openRightPanel('data-sources')
}, [startNewSessionDraft, clearSessionUrl, openRightPanel])

// Wrap deleteConversation to clear URL if deleting current session
const handleDeleteSession = useCallback(
Expand Down
8 changes: 5 additions & 3 deletions frontends/ui/src/features/layout/store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { useLayoutStore } from './store'

describe('useLayoutStore', () => {
beforeEach(() => {
// Reset store to initial state before each test
// Reset store to initial state before each test (matches store.ts initialState)
useLayoutStore.setState({
isSessionsPanelOpen: false,
rightPanel: null,
rightPanel: 'data-sources',
researchPanelTab: 'plan',
dataSourcesPanelTab: 'connections',
theme: 'system',
Expand All @@ -21,7 +21,7 @@ describe('useLayoutStore', () => {
const state = useLayoutStore.getState()

expect(state.isSessionsPanelOpen).toBe(false)
expect(state.rightPanel).toBeNull()
expect(state.rightPanel).toBe('data-sources')
expect(state.researchPanelTab).toBe('plan')
expect(state.dataSourcesPanelTab).toBe('connections')
})
Expand Down Expand Up @@ -110,6 +110,8 @@ describe('useLayoutStore', () => {
})

test('handles closing when already closed', () => {
useLayoutStore.setState({ rightPanel: null })

useLayoutStore.getState().closeRightPanel()

expect(useLayoutStore.getState().rightPanel).toBeNull()
Expand Down
3 changes: 2 additions & 1 deletion frontends/ui/src/features/layout/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { WEB_SEARCH_SOURCE_ID } from './data-sources'

const initialState: LayoutState = {
isSessionsPanelOpen: false,
rightPanel: null,
rightPanel: 'data-sources',
researchPanelTab: 'plan',
dataSourcesPanelTab: 'connections',
enabledDataSourceIds: [], // Start empty, populated when data sources are fetched
Expand Down Expand Up @@ -91,6 +91,7 @@ export const useLayoutStore = create<LayoutStore>()(

// data_sources is already filtered (knowledge_layer removed) by the client
// Only enable web_search by default - user must manually enable other sources
// This ensures ECI sources are opt-in and prevents accidental data access
const enabledIds = response.data_sources
.filter((source) => source.id === WEB_SEARCH_SOURCE_ID)
.map((source) => source.id)
Expand Down
2 changes: 1 addition & 1 deletion frontends/ui/src/features/layout/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export interface LayoutActions {
setTheme: (theme: ThemeMode) => void
/** Fetch data sources from API. Only web_search is enabled by default */
fetchDataSources: (authToken?: string) => Promise<void>
/** Disable all non-web sources (keep only web_search enabled) */
/** Disable non-web sources (keep only web_search enabled) */
disableNonWebSources: () => void
/** Set available data sources (from API) */
setAvailableDataSources: (sources: DataSourceFromAPI[]) => void
Expand Down
Loading