diff --git a/desktop/src/components/controls/ModelSelector.test.tsx b/desktop/src/components/controls/ModelSelector.test.tsx index 62f65dab..78277703 100644 --- a/desktop/src/components/controls/ModelSelector.test.tsx +++ b/desktop/src/components/controls/ModelSelector.test.tsx @@ -1,4 +1,4 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { act, cleanup, fireEvent, render, screen } from '@testing-library/react' import '@testing-library/jest-dom' @@ -34,6 +34,12 @@ afterEach(() => { useHahaOpenAIOAuthStore.setState(useHahaOpenAIOAuthStore.getInitialState(), true) }) +// Prevent real API calls from fetchStatus on mount +beforeEach(() => { + useHahaOAuthStore.setState({ fetchStatus: async () => {} }) + useHahaOpenAIOAuthStore.setState({ fetchStatus: async () => {} }) +}) + describe('ModelSelector', () => { it('uses controlled model selection without mutating settings directly', async () => { const onChange = vi.fn() @@ -139,7 +145,10 @@ describe('ModelSelector', () => { }, ] const setSessionRuntime = vi.fn() - useHahaOpenAIOAuthStore.setState({ status: { loggedIn: true, expiresAt: null, email: null, accountId: null } }) + useHahaOpenAIOAuthStore.setState({ + status: { loggedIn: true, expiresAt: null, email: null, accountId: null }, + fetchStatus: async () => {}, + }) useSettingsStore.setState({ locale: 'en', availableModels: openAIModels, @@ -175,8 +184,8 @@ describe('ModelSelector', () => { }) it('hides official provider sections when OAuth is not logged in', async () => { - useHahaOAuthStore.setState({ status: { loggedIn: false } }) - useHahaOpenAIOAuthStore.setState({ status: { loggedIn: false } }) + useHahaOAuthStore.setState({ status: { loggedIn: false }, fetchStatus: async () => {} }) + useHahaOpenAIOAuthStore.setState({ status: { loggedIn: false }, fetchStatus: async () => {} }) useSettingsStore.setState({ locale: 'en', availableModels: MODELS, diff --git a/desktop/src/components/controls/ModelSelector.tsx b/desktop/src/components/controls/ModelSelector.tsx index 0b38c88a..45e651d2 100644 --- a/desktop/src/components/controls/ModelSelector.tsx +++ b/desktop/src/components/controls/ModelSelector.tsx @@ -38,7 +38,8 @@ type Props = { } type DropdownPosition = { - top: number + top: number | undefined + bottom: number | undefined left: number width: number maxHeight: number @@ -267,9 +268,8 @@ export function ModelSelector({ const maxHeight = Math.min(DROPDOWN_MAX_HEIGHT, availableHeight) setDropdownPosition({ - top: placeBelow - ? rect.bottom + DROPDOWN_GAP - : Math.max(VIEWPORT_MARGIN, rect.top - DROPDOWN_GAP - maxHeight), + top: placeBelow ? rect.bottom + DROPDOWN_GAP : undefined, + bottom: placeBelow ? undefined : (viewportHeight - rect.top + DROPDOWN_GAP), left, width, maxHeight, @@ -535,6 +535,7 @@ export function ModelSelector({ className="fixed z-[80] rounded-xl border border-[var(--color-border)] bg-[var(--color-surface-container-lowest)] shadow-[var(--shadow-dropdown)]" style={{ top: dropdownPosition.top, + bottom: dropdownPosition.bottom, left: dropdownPosition.left, width: dropdownPosition.width, }}