1- import { useCallback , useState } from "react"
2- import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
1+ import { useCallback , useEffect , useRef , useState } from "react"
2+ import { VSCodeLink , VSCodeProgressRing , VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
33
44import type { ProviderSettings } from "@roo-code/types"
55
@@ -14,14 +14,47 @@ import { Tab, TabContent } from "../common/Tab"
1414
1515import RooHero from "./RooHero"
1616import { Trans } from "react-i18next"
17+ import { ArrowLeft } from "lucide-react"
1718
1819type ProviderOption = "roo" | "custom"
1920
2021const WelcomeViewProvider = ( ) => {
21- const { apiConfiguration, currentApiConfigName, setApiConfiguration, uriScheme } = useExtensionState ( )
22+ const { apiConfiguration, currentApiConfigName, setApiConfiguration, uriScheme, cloudIsAuthenticated } =
23+ useExtensionState ( )
2224 const { t } = useAppTranslation ( )
2325 const [ errorMessage , setErrorMessage ] = useState < string | undefined > ( undefined )
2426 const [ selectedProvider , setSelectedProvider ] = useState < ProviderOption > ( "roo" )
27+ const [ authInProgress , setAuthInProgress ] = useState ( false )
28+ const [ showManualEntry , setShowManualEntry ] = useState ( false )
29+ const [ manualUrl , setManualUrl ] = useState ( "" )
30+ const manualUrlInputRef = useRef < HTMLInputElement | null > ( null )
31+
32+ // When auth completes during the provider signup flow, save the Roo config
33+ // This will cause showWelcome to become false and navigate to chat
34+ useEffect ( ( ) => {
35+ if ( cloudIsAuthenticated && authInProgress ) {
36+ // Auth completed from provider signup flow - save the config now
37+ const rooConfig : ProviderSettings = {
38+ apiProvider : "roo" ,
39+ }
40+ vscode . postMessage ( {
41+ type : "upsertApiConfiguration" ,
42+ text : currentApiConfigName ,
43+ apiConfiguration : rooConfig ,
44+ } )
45+ setAuthInProgress ( false )
46+ setShowManualEntry ( false )
47+ }
48+ } , [ cloudIsAuthenticated , authInProgress , currentApiConfigName ] )
49+
50+ // Focus the manual URL input when it becomes visible
51+ useEffect ( ( ) => {
52+ if ( showManualEntry && manualUrlInputRef . current ) {
53+ setTimeout ( ( ) => {
54+ manualUrlInputRef . current ?. focus ( )
55+ } , 50 )
56+ }
57+ } , [ showManualEntry ] )
2558
2659 // Memoize the setApiConfigurationField function to pass to ApiOptions
2760 const setApiConfigurationFieldForApiOptions = useCallback (
@@ -33,20 +66,14 @@ const WelcomeViewProvider = () => {
3366
3467 const handleGetStarted = useCallback ( ( ) => {
3568 if ( selectedProvider === "roo" ) {
36- // Set the Roo provider configuration
37- const rooConfig : ProviderSettings = {
38- apiProvider : "roo" ,
39- }
40-
41- // Save the Roo provider configuration
42- vscode . postMessage ( {
43- type : "upsertApiConfiguration" ,
44- text : currentApiConfigName ,
45- apiConfiguration : rooConfig ,
46- } )
47-
48- // Then trigger cloud sign-in with provider signup flow
69+ // Trigger cloud sign-in with provider signup flow
70+ // NOTE: We intentionally do NOT save the API configuration yet.
71+ // The configuration will be saved by the extension after auth completes.
72+ // This keeps showWelcome true so we can show the waiting state.
4973 vscode . postMessage ( { type : "rooCloudSignIn" , useProviderSignup : true } )
74+
75+ // Show the waiting state
76+ setAuthInProgress ( true )
5077 } else {
5178 // Use custom provider - validate first
5279 const error = apiConfiguration ? validateApiConfiguration ( apiConfiguration ) : undefined
@@ -61,6 +88,104 @@ const WelcomeViewProvider = () => {
6188 }
6289 } , [ selectedProvider , apiConfiguration , currentApiConfigName ] )
6390
91+ const handleGoBack = useCallback ( ( ) => {
92+ setAuthInProgress ( false )
93+ setShowManualEntry ( false )
94+ setManualUrl ( "" )
95+ } , [ ] )
96+
97+ const handleManualUrlChange = ( e : any ) => {
98+ const url = e . target . value
99+ setManualUrl ( url )
100+
101+ // Auto-trigger authentication when a complete URL is pasted
102+ setTimeout ( ( ) => {
103+ if ( url . trim ( ) && url . includes ( "://" ) && url . includes ( "/auth/clerk/callback" ) ) {
104+ vscode . postMessage ( { type : "rooCloudManualUrl" , text : url . trim ( ) } )
105+ }
106+ } , 100 )
107+ }
108+
109+ const handleKeyDown = ( e : any ) => {
110+ if ( e . key === "Enter" ) {
111+ const url = manualUrl . trim ( )
112+ if ( url && url . includes ( "://" ) && url . includes ( "/auth/clerk/callback" ) ) {
113+ vscode . postMessage ( { type : "rooCloudManualUrl" , text : url } )
114+ }
115+ }
116+ }
117+
118+ const handleOpenSignupUrl = ( ) => {
119+ vscode . postMessage ( { type : "rooCloudSignIn" , useProviderSignup : true } )
120+ }
121+
122+ // Render the waiting for cloud state
123+ if ( authInProgress ) {
124+ return (
125+ < Tab >
126+ < TabContent className = "flex flex-col gap-4 p-6" >
127+ < div className = "flex flex-col items-start gap-4 pt-8" >
128+ < VSCodeProgressRing className = "size-6" />
129+ < h2 className = "mt-0 mb-0 text-lg font-semibold" > { t ( "welcome:waitingForCloud.heading" ) } </ h2 >
130+ < p className = "text-sm text-vscode-descriptionForeground mt-0" >
131+ { t ( "welcome:waitingForCloud.description" ) }
132+ </ p >
133+
134+ < p className = "text-sm text-vscode-descriptionForeground mt-2" >
135+ < Trans
136+ i18nKey = "welcome:waitingForCloud.noPrompt"
137+ components = { {
138+ clickHere : (
139+ < button
140+ onClick = { handleOpenSignupUrl }
141+ className = "text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground underline cursor-pointer bg-transparent border-none p-0 text-sm"
142+ />
143+ ) ,
144+ } }
145+ />
146+ </ p >
147+
148+ < p className = "text-sm text-vscode-descriptionForeground" >
149+ < Trans
150+ i18nKey = "welcome:waitingForCloud.havingTrouble"
151+ components = { {
152+ clickHere : (
153+ < button
154+ onClick = { ( ) => setShowManualEntry ( true ) }
155+ className = "text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground underline cursor-pointer bg-transparent border-none p-0 text-sm"
156+ />
157+ ) ,
158+ } }
159+ />
160+ </ p >
161+
162+ { showManualEntry && (
163+ < div className = "mt-2 w-full max-w-sm" >
164+ < p className = "text-sm text-vscode-descriptionForeground mb-2" >
165+ Paste the callback URL from your browser:
166+ </ p >
167+ < VSCodeTextField
168+ ref = { manualUrlInputRef as any }
169+ value = { manualUrl }
170+ onChange = { handleManualUrlChange }
171+ onKeyDown = { handleKeyDown }
172+ placeholder = "vscode://RooVeterinaryInc.roo-cline/auth/clerk/callback?state=..."
173+ className = "w-full"
174+ />
175+ </ div >
176+ ) }
177+ </ div >
178+ </ TabContent >
179+ < div className = "sticky bottom-0 bg-vscode-sideBar-background p-4 border-t border-vscode-panel-border" >
180+ < Button onClick = { handleGoBack } variant = "secondary" className = "flex items-center gap-2" >
181+ < ArrowLeft className = "size-4" />
182+ { t ( "welcome:waitingForCloud.goBack" ) }
183+ </ Button >
184+ </ div >
185+ </ Tab >
186+ )
187+ }
188+
64189 return (
65190 < Tab >
66191 < TabContent className = "flex flex-col gap-4 p-6" >
0 commit comments