@@ -44,6 +44,9 @@ export interface RemoteDetails extends vscode.Disposable {
44
44
}
45
45
46
46
export class Remote {
47
+ private loginDetectedResolver : ( ( ) => void ) | undefined ;
48
+ private loginDetectedPromise : Promise < void > = Promise . resolve ( ) ;
49
+
47
50
public constructor (
48
51
// We use the proposed API to get access to useCustom in dialogs.
49
52
private readonly vscodeProposed : typeof vscode ,
@@ -54,6 +57,27 @@ export class Remote {
54
57
private readonly cliManager : CliManager ,
55
58
) { }
56
59
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
+
57
81
private async confirmStart ( workspaceName : string ) : Promise < boolean > {
58
82
const action = await this . vscodeProposed . window . showInformationMessage (
59
83
`Unable to connect to the workspace ${ workspaceName } because it is not running. Start the workspace?` ,
@@ -206,6 +230,8 @@ export class Remote {
206
230
remoteAuthority : string ,
207
231
firstConnect : boolean ,
208
232
) : Promise < RemoteDetails | undefined > {
233
+ this . createLoginDetectionPromise ( ) ;
234
+
209
235
const parts = parseRemoteAuthority ( remoteAuthority ) ;
210
236
if ( ! parts ) {
211
237
// Not a Coder host.
@@ -218,7 +244,7 @@ export class Remote {
218
244
await this . migrateSessionToken ( parts . label ) ;
219
245
220
246
// 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 (
222
248
parts . label ,
223
249
) ;
224
250
@@ -227,24 +253,38 @@ export class Remote {
227
253
! baseUrlRaw ||
228
254
( ! token && needToken ( vscode . workspace . getConfiguration ( ) ) )
229
255
) {
230
- const result = await this . vscodeProposed . window . showInformationMessage (
256
+ const dialogPromise = this . vscodeProposed . window . showInformationMessage (
231
257
"You are not logged in..." ,
232
258
{
233
259
useCustom : true ,
234
260
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. ` ,
236
262
} ,
237
263
"Log In" ,
238
264
) ;
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 ) ;
242
277
} 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
+ }
246
287
}
247
- return ;
248
288
}
249
289
250
290
this . logger . info ( "Using deployment URL" , baseUrlRaw ) ;
@@ -360,11 +400,11 @@ export class Remote {
360
400
) ;
361
401
if ( ! result ) {
362
402
await this . closeRemote ( ) ;
403
+ return ;
363
404
} else {
364
405
await this . commands . login ( { url : baseUrlRaw , label : parts . label } ) ;
365
- await this . setup ( remoteAuthority , firstConnect ) ;
406
+ return this . setup ( remoteAuthority , firstConnect ) ;
366
407
}
367
- return ;
368
408
}
369
409
default :
370
410
throw error ;
0 commit comments