@@ -5,6 +5,7 @@ import { SetupModal } from './SetupModal';
55import { startOpenRouterSetup } from '../utils/openRouterSetup' ;
66import { startTetrateSetup } from '../utils/tetrateSetup' ;
77import { startChatGptCodexSetup } from '../utils/chatgptCodexSetup' ;
8+ import { cancelTetrateSetup } from '../utils/tetrateSetup' ;
89import WelcomeGooseLogo from './WelcomeGooseLogo' ;
910import { toastService } from '../toasts' ;
1011import { OllamaSetup } from './OllamaSetup' ;
@@ -37,7 +38,9 @@ export default function ProviderGuard({ didSelectProvider, children }: ProviderG
3738 const [ userInActiveSetup , setUserInActiveSetup ] = useState ( false ) ;
3839 const [ showSwitchModelModal , setShowSwitchModelModal ] = useState ( false ) ;
3940 const [ switchModelProvider , setSwitchModelProvider ] = useState < string | null > ( null ) ;
41+ const [ isTetrateSetupInProgress , setIsTetrateSetupInProgress ] = useState ( false ) ;
4042 const onboardingTracked = useRef ( false ) ;
43+ const tetrateSetupRunId = useRef ( 0 ) ;
4144 const scrollContainerRef = useRef < HTMLDivElement > ( null ) ;
4245 const [ showScrollIndicator , setShowScrollIndicator ] = useState ( true ) ;
4346
@@ -66,7 +69,9 @@ export default function ProviderGuard({ didSelectProvider, children }: ProviderG
6669 show : boolean ;
6770 title : string ;
6871 message : string ;
72+ showProgress ?: boolean ;
6973 showRetry : boolean ;
74+ closeLabel ?: string ;
7075 autoClose ?: number ;
7176 } | null > ( null ) ;
7277
@@ -79,10 +84,31 @@ export default function ProviderGuard({ didSelectProvider, children }: ProviderG
7984 } | null > ( null ) ;
8085
8186 const handleTetrateSetup = async ( ) => {
87+ if ( isTetrateSetupInProgress ) {
88+ return ;
89+ }
90+
91+ const runId = ++ tetrateSetupRunId . current ;
92+ setIsTetrateSetupInProgress ( true ) ;
93+ setTetrateSetupState ( {
94+ show : true ,
95+ title : 'Complete setup in your browser' ,
96+ message : 'After finishing sign-in in the browser, return to Goose. You can cancel setup anytime.' ,
97+ showProgress : true ,
98+ showRetry : false ,
99+ closeLabel : 'Cancel Setup' ,
100+ } ) ;
82101 trackOnboardingProviderSelected ( 'tetrate' ) ;
83102 try {
84103 const result = await startTetrateSetup ( ) ;
104+ if ( runId !== tetrateSetupRunId . current ) {
105+ return ;
106+ }
107+
108+ setIsTetrateSetupInProgress ( false ) ;
109+
85110 if ( result . success ) {
111+ setTetrateSetupState ( null ) ;
86112 setSwitchModelProvider ( 'tetrate' ) ;
87113 setShowSwitchModelModal ( true ) ;
88114 } else {
@@ -95,6 +121,11 @@ export default function ProviderGuard({ didSelectProvider, children }: ProviderG
95121 } ) ;
96122 }
97123 } catch ( error ) {
124+ if ( runId !== tetrateSetupRunId . current ) {
125+ return ;
126+ }
127+
128+ setIsTetrateSetupInProgress ( false ) ;
98129 console . error ( 'Tetrate setup error:' , error ) ;
99130 trackOnboardingSetupFailed ( 'tetrate' , 'unexpected_error' ) ;
100131 setTetrateSetupState ( {
@@ -134,6 +165,19 @@ export default function ProviderGuard({ didSelectProvider, children }: ProviderG
134165 }
135166 } ;
136167
168+ const handleCancelTetrateSetup = async ( ) => {
169+ if ( ! isTetrateSetupInProgress ) {
170+ setTetrateSetupState ( null ) ;
171+ return ;
172+ }
173+
174+ tetrateSetupRunId . current += 1 ;
175+ setIsTetrateSetupInProgress ( false ) ;
176+ setTetrateSetupState ( null ) ;
177+ trackOnboardingAbandoned ( 'tetrate_setup' ) ;
178+ await cancelTetrateSetup ( ) ;
179+ } ;
180+
137181 const handleApiKeySuccess = async ( provider : string , _model : string , apiKey : string ) => {
138182 trackOnboardingProviderSelected ( 'api_key' ) ;
139183 const keyName = `${ provider . toUpperCase ( ) } _API_KEY` ;
@@ -217,7 +261,7 @@ export default function ProviderGuard({ didSelectProvider, children }: ProviderG
217261 if ( setupType === 'openrouter' ) {
218262 setOpenRouterSetupState ( null ) ;
219263 } else if ( setupType === 'tetrate' ) {
220- setTetrateSetupState ( null ) ;
264+ void handleCancelTetrateSetup ( ) ;
221265 } else {
222266 setChatgptCodexSetupState ( null ) ;
223267 }
@@ -366,8 +410,12 @@ export default function ProviderGuard({ didSelectProvider, children }: ProviderG
366410 </ div >
367411
368412 < div
369- onClick = { handleTetrateSetup }
370- className = "w-full p-4 sm:p-6 bg-transparent border rounded-xl transition-all duration-200 cursor-pointer group"
413+ onClick = { isTetrateSetupInProgress ? undefined : handleTetrateSetup }
414+ className = { `w-full p-4 sm:p-6 bg-transparent border border-background-hover rounded-xl transition-all duration-200 group ${
415+ isTetrateSetupInProgress
416+ ? 'cursor-not-allowed opacity-70'
417+ : 'cursor-pointer hover:border-text-muted'
418+ } `}
371419 >
372420 < div className = "flex items-start justify-between mb-3" >
373421 < div className = "flex items-center gap-2" >
@@ -490,9 +538,11 @@ export default function ProviderGuard({ didSelectProvider, children }: ProviderG
490538 < SetupModal
491539 title = { tetrateSetupState . title }
492540 message = { tetrateSetupState . message }
541+ showProgress = { tetrateSetupState . showProgress }
493542 showRetry = { tetrateSetupState . showRetry }
494543 onRetry = { ( ) => handleRetrySetup ( 'tetrate' ) }
495544 onClose = { ( ) => closeSetupModal ( 'tetrate' ) }
545+ closeLabel = { tetrateSetupState . closeLabel }
496546 autoClose = { tetrateSetupState . autoClose }
497547 />
498548 ) }
0 commit comments