diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index b89a20ed..ad65adc6 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -33,6 +33,7 @@ import { InputPrompt } from './components/InputPrompt.js'; import { Footer } from './components/Footer.js'; import { ThemeDialog } from './components/ThemeDialog.js'; import { AuthDialog } from './components/AuthDialog.js'; +import { AuthInProgress } from './components/AuthInProgress.js'; import { EditorSettingsDialog } from './components/EditorSettingsDialog.js'; import { Colors } from './colors.js'; import { Help } from './components/Help.js'; @@ -138,6 +139,8 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { openAuthDialog, handleAuthSelect, handleAuthHighlight, + isAuthenticating, + cancelAuthentication, } = useAuthCommand(settings, setAuthError, config); useEffect(() => { @@ -585,6 +588,14 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { terminalWidth={mainAreaWidth} /> + ) : isAuthenticating ? ( + { + setAuthError('Authentication timed out. Please try again.'); + cancelAuthentication(); + openAuthDialog(); + }} + /> ) : isAuthDialogOpen ? ( void; +} + +export function AuthInProgress({ + onTimeout, +}: AuthInProgressProps): React.JSX.Element { + const [timedOut, setTimedOut] = useState(false); + + useEffect(() => { + const timer = setTimeout(() => { + setTimedOut(true); + onTimeout(); + }, 30000); + + return () => clearTimeout(timer); + }, [onTimeout]); + + return ( + + {timedOut ? ( + + Authentication timed out. Please try again. + + ) : ( + + + Waiting for auth... + + + )} + + ); +} diff --git a/packages/cli/src/ui/hooks/useAuthCommand.ts b/packages/cli/src/ui/hooks/useAuthCommand.ts index 2c2b5f93..5cc67a07 100644 --- a/packages/cli/src/ui/hooks/useAuthCommand.ts +++ b/packages/cli/src/ui/hooks/useAuthCommand.ts @@ -31,6 +31,8 @@ export const useAuthCommand = ( setIsAuthDialogOpen(true); }, []); + const [isAuthenticating, setIsAuthenticating] = useState(false); + useEffect(() => { const authFlow = async () => { if (isAuthDialogOpen || !settings.merged.selectedAuthType) { @@ -38,6 +40,7 @@ export const useAuthCommand = ( } try { + setIsAuthenticating(true); await performAuthFlow( settings.merged.selectedAuthType as AuthType, config, @@ -51,6 +54,8 @@ Message: ${getErrorMessage(e)}` : `Failed to login. Message: ${getErrorMessage(e)}`; setAuthError(errorMessage); openAuthDialog(); + } finally { + setIsAuthenticating(false); } }; @@ -73,10 +78,16 @@ Message: ${getErrorMessage(e)}` // For now, we don't do anything on highlight. }, []); + const cancelAuthentication = useCallback(() => { + setIsAuthenticating(false); + }, []); + return { isAuthDialogOpen, openAuthDialog, handleAuthSelect, handleAuthHighlight, + isAuthenticating, + cancelAuthentication, }; };