fix(desktop): wait for first-run bootstrap before connection timeout

This commit is contained in:
2026-09-05 13:46:53 +03:00
parent 03634b1ca3
commit b9bb62ea82
6 changed files with 231 additions and 30 deletions
@@ -15,6 +15,7 @@ import type {
DesktopBootstrapState
} from '@/global'
import { useI18n } from '@/i18n'
import { aiturkInstallStage } from '@/i18n/aiturk'
import { AlertCircle, ChevronDown, ChevronRight, Globe, iconSize, Loader2, Monitor } from '@/lib/icons'
import { capitalize } from '@/lib/text'
import { cn } from '@/lib/utils'
@@ -59,6 +60,10 @@ interface StageRowProps {
}
function formatStageName(name: string): string {
const translated = aiturkInstallStage(name)
if (translated) {
return translated
}
// 'system-packages' -> 'System packages'; 'uv' stays 'uv'
if (name.length <= 3) {
return name
@@ -270,6 +270,12 @@ export function DesktopOnboardingOverlay({
// do we know whether to dismiss (true) or surface the picker (false).
// EXCEPTION: manual mode (user opened the selector from a working app to
// add/switch a provider) shows the overlay regardless of configured state.
// The local installer owns first-run choice and download progress. Provider
// onboarding becomes meaningful after that runtime is available.
if (boot.running && boot.phase === 'bootstrap.choice' && !onboarding.manual) {
return null
}
if (onboarding.configured === true && !onboarding.manual) {
return null
}
@@ -446,7 +452,13 @@ export function Picker({ ctx }: { ctx: OnboardingContext }) {
const ordered = useMemo(() => (providers ? sortProviders(providers) : []), [providers])
const hasOauth = ordered.length > 0
const apiKeyOptions = useApiKeyCatalog()
const aiturkProvider = <AiturkProvider onConnected={async () => { await refreshOnboarding(ctx) }} />
const aiturkProvider = (
<AiturkProvider
onConnected={async () => {
await refreshOnboarding(ctx)
}}
/>
)
// localEndpoint forces the key form regardless of `mode` (which a manual
// provider refresh may flip back to 'oauth'); it preselects the local option
@@ -674,7 +686,9 @@ export function ApiKeyForm({
type="button"
>
<div className="flex items-center justify-between gap-2">
<span className="text-sm font-medium">{o.id === 'local' ? t.settings.providers.localEndpoint.title : o.name}</span>
<span className="text-sm font-medium">
{o.id === 'local' ? t.settings.providers.localEndpoint.title : o.name}
</span>
{isSet?.(o.envKey) ? <Check className="size-3.5 text-muted-foreground" /> : null}
</div>
{(t.onboarding.apiKeyOptions[o.id]?.short ?? o.short) ? (