import React from 'react'; import { isDesktopShell, restartDesktopApp } from '@/lib/desktop'; import { DesktopConnectionRecovery, type RecoveryVariant } from './DesktopConnectionRecovery'; import { RemoteConnectionForm } from './RemoteConnectionForm'; import { resolveRecoveryNextStep } from './desktopRecoveryRouting'; import { desktopHostsGet, desktopHostsSet } from '@/lib/desktopHosts'; import { runtimeFetch } from '@/lib/runtime-fetch'; type RecoveryScreenProps = { /** Recovery variant */ variant: RecoveryVariant; /** Host URL for recovery context */ hostUrl?: string; /** Host label for recovery context */ hostLabel?: string; /** Callback when user wants to retry */ onRetry?: () => void; /** Callback when user chooses remote */ onChooseRemote?: () => void; /** Whether to show the remote connection form */ showRemoteForm?: boolean; /** Callback when closing remote form */ onCloseRemoteForm?: () => void; /** Callback when switching to local from remote form */ onSwitchToLocalFromRemote?: () => void; /** Callback when entering local setup */ onEnterLocalSetup?: () => void; /** Whether retry action is in progress */ isRetrying?: boolean; localAvailable?: boolean; }; export function RecoveryScreen({ variant, hostUrl, hostLabel, onRetry, onChooseRemote, showRemoteForm = false, onCloseRemoteForm, onSwitchToLocalFromRemote, onEnterLocalSetup, isRetrying = false, localAvailable = true, }: RecoveryScreenProps) { // Persist the user's first choice (local or remote) const persistFirstChoice = React.useCallback(async (choice: 'local' | 'remote') => { if (!isDesktopShell()) return; const config = await desktopHostsGet(); await desktopHostsSet({ ...config, // Only change defaultHostId when switching to local; remote keeps // whatever was there (or null) until a successful connect. ...(choice === 'local' ? { defaultHostId: 'local' } : {}), initialHostChoiceCompleted: true, }); }, []); const handleRecoveryRetry = React.useCallback(async () => { // In desktop boot flow, restart the app so the native host can // re-evaluate the boot outcome. if (isDesktopShell()) { await restartDesktopApp(); return; } await runtimeFetch('/api/config/reload', { method: 'POST' }); onRetry?.(); }, [onRetry]); const handleRecoveryUseLocal = React.useCallback(async () => { const step = resolveRecoveryNextStep(variant, 'use-local'); if (step.kind === 'local-setup') { // local-unavailable + local → enter local-setup subflow without reload onEnterLocalSetup?.(); return; } // switch-default-to-local → persist local choice and restart await persistFirstChoice('local'); if (isDesktopShell()) { await restartDesktopApp(); return; } window.location.reload(); }, [variant, persistFirstChoice, onEnterLocalSetup]); const handleRecoveryUseRemote = React.useCallback(() => { const step = resolveRecoveryNextStep(variant, 'use-remote'); if (step.kind === 'remote-form') { onChooseRemote?.(); } }, [variant, onChooseRemote]); // Recovery mode — show recovery component first; only switch to remote form on explicit user action if (showRemoteForm) { // For remote-wrong-service, do NOT auto-populate the known bad URL const prefillUrl = variant === 'remote-wrong-service' ? '' : (hostUrl || ''); const prefillLabel = variant === 'remote-wrong-service' ? '' : (hostLabel || ''); return ( onChooseRemote?.())} initialUrl={prefillUrl} initialLabel={prefillLabel} isRecoveryMode={true} showInstancePicker={!localAvailable} onSwitchToLocal={localAvailable ? (onSwitchToLocalFromRemote || (() => { persistFirstChoice('local').then(() => { if (isDesktopShell()) { restartDesktopApp(); } else { onEnterLocalSetup?.(); } }); })) : undefined} /> ); } return ( ); }