@@ -44,6 +44,9 @@ export interface RemoteDetails extends vscode.Disposable {
4444}
4545
4646export class Remote {
47+ private loginDetectedResolver : ( ( ) => void ) | undefined ;
48+ private loginDetectedPromise : Promise < void > = Promise . resolve ( ) ;
49+
4750 public constructor (
4851 // We use the proposed API to get access to useCustom in dialogs.
4952 private readonly vscodeProposed : typeof vscode ,
@@ -54,6 +57,27 @@ export class Remote {
5457 private readonly cliManager : CliManager ,
5558 ) { }
5659
60+ /**
61+ * Creates a new promise that will be resolved when login is detected in another window.
62+ * This should be called when starting a setup operation that might need login.
63+ */
64+ private createLoginDetectionPromise ( ) : void {
65+ this . loginDetectedPromise = new Promise < void > ( ( resolve ) => {
66+ this . loginDetectedResolver = resolve ;
67+ } ) ;
68+ }
69+
70+ /**
71+ * Resolves the current login detection promise if one exists.
72+ * This should be called from the extension when login is detected.
73+ */
74+ public resolveLoginDetected ( ) : void {
75+ if ( this . loginDetectedResolver ) {
76+ this . loginDetectedResolver ( ) ;
77+ this . loginDetectedResolver = undefined ;
78+ }
79+ }
80+
5781 private async confirmStart ( workspaceName : string ) : Promise < boolean > {
5882 const action = await this . vscodeProposed . window . showInformationMessage (
5983 `Unable to connect to the workspace ${ workspaceName } because it is not running. Start the workspace?` ,
@@ -206,6 +230,8 @@ export class Remote {
206230 remoteAuthority : string ,
207231 firstConnect : boolean ,
208232 ) : Promise < RemoteDetails | undefined > {
233+ this . createLoginDetectionPromise ( ) ;
234+
209235 const parts = parseRemoteAuthority ( remoteAuthority ) ;
210236 if ( ! parts ) {
211237 // Not a Coder host.
@@ -218,7 +244,7 @@ export class Remote {
218244 await this . migrateSessionToken ( parts . label ) ;
219245
220246 // Get the URL and token belonging to this host.
221- const { url : baseUrlRaw , token } = await this . cliManager . readConfig (
247+ let { url : baseUrlRaw , token } = await this . cliManager . readConfig (
222248 parts . label ,
223249 ) ;
224250
@@ -227,24 +253,38 @@ export class Remote {
227253 ! baseUrlRaw ||
228254 ( ! token && needToken ( vscode . workspace . getConfiguration ( ) ) )
229255 ) {
230- const result = await this . vscodeProposed . window . showInformationMessage (
256+ const dialogPromise = this . vscodeProposed . window . showInformationMessage (
231257 "You are not logged in..." ,
232258 {
233259 useCustom : true ,
234260 modal : true ,
235- detail : `You must log in to access ${ workspaceName } .` ,
261+ detail : `You must log in to access ${ workspaceName } . If you've already logged in, you may close this dialog. ` ,
236262 } ,
237263 "Log In" ,
238264 ) ;
239- if ( ! result ) {
240- // User declined to log in.
241- await this . closeRemote ( ) ;
265+
266+ // Race between dialog and login detection
267+ const result = await Promise . race ( [
268+ this . loginDetectedPromise . then ( ( ) => ( { type : "login" as const } ) ) ,
269+ dialogPromise . then ( ( userChoice ) => ( {
270+ type : "dialog" as const ,
271+ userChoice,
272+ } ) ) ,
273+ ] ) ;
274+
275+ if ( result . type === "login" ) {
276+ return this . setup ( remoteAuthority , firstConnect ) ;
242277 } else {
243- // Log in then try again.
244- await this . commands . login ( { url : baseUrlRaw , label : parts . label } ) ;
245- await this . setup ( remoteAuthority , firstConnect ) ;
278+ if ( ! result . userChoice ) {
279+ // User declined to log in.
280+ await this . closeRemote ( ) ;
281+ return ;
282+ } else {
283+ // Log in then try again.
284+ await this . commands . login ( { url : baseUrlRaw , label : parts . label } ) ;
285+ return this . setup ( remoteAuthority , firstConnect ) ;
286+ }
246287 }
247- return ;
248288 }
249289
250290 this . logger . info ( "Using deployment URL" , baseUrlRaw ) ;
@@ -360,11 +400,11 @@ export class Remote {
360400 ) ;
361401 if ( ! result ) {
362402 await this . closeRemote ( ) ;
403+ return ;
363404 } else {
364405 await this . commands . login ( { url : baseUrlRaw , label : parts . label } ) ;
365- await this . setup ( remoteAuthority , firstConnect ) ;
406+ return this . setup ( remoteAuthority , firstConnect ) ;
366407 }
367- return ;
368408 }
369409 default :
370410 throw error ;
0 commit comments