@@ -77,7 +77,6 @@ import {
77
77
terminalWithDocker ,
78
78
notNull ,
79
79
currentFile ,
80
- InputBoxManager ,
81
80
isImportableLocalFile ,
82
81
workspaceFolderOfUri ,
83
82
uriOfWorkspaceFolder ,
@@ -212,7 +211,8 @@ export async function resolvePassword(serverSpec): Promise<void> {
212
211
session = await vscode . authentication . getSession ( AUTHENTICATION_PROVIDER , scopes , { createIfNone : true } ) ;
213
212
}
214
213
if ( session ) {
215
- serverSpec . username = session . scopes [ 1 ] ;
214
+ // If original spec lacked username use the one obtained by the authprovider
215
+ serverSpec . username = serverSpec . username || session . scopes [ 1 ] ;
216
216
serverSpec . password = session . accessToken ;
217
217
}
218
218
}
@@ -240,11 +240,11 @@ export async function checkConnection(clearCookies = false, uri?: vscode.Uri): P
240
240
const { apiTarget, configName } = connectionTarget ( uri ) ;
241
241
if ( clearCookies ) {
242
242
/// clean-up cached values
243
- workspaceState . update ( configName + ":host" , undefined ) ;
244
- workspaceState . update ( configName + ":port" , undefined ) ;
245
- workspaceState . update ( configName + ":password" , undefined ) ;
246
- workspaceState . update ( configName + ":apiVersion" , undefined ) ;
247
- workspaceState . update ( configName + ":docker" , undefined ) ;
243
+ await workspaceState . update ( configName + ":host" , undefined ) ;
244
+ await workspaceState . update ( configName + ":port" , undefined ) ;
245
+ await workspaceState . update ( configName + ":password" , undefined ) ;
246
+ await workspaceState . update ( configName + ":apiVersion" , undefined ) ;
247
+ await workspaceState . update ( configName + ":docker" , undefined ) ;
248
248
_onDidChangeConnection . fire ( ) ;
249
249
}
250
250
let api = new AtelierAPI ( apiTarget , false ) ;
@@ -303,75 +303,111 @@ export async function checkConnection(clearCookies = false, uri?: vscode.Uri): P
303
303
api . clearCookies ( ) ;
304
304
}
305
305
306
- // Why must this be recreated here?
306
+ // Why must this be recreated here? Maybe in case something has updated connection details since we last fetched them.
307
307
api = new AtelierAPI ( apiTarget , false ) ;
308
308
309
309
if ( ! api . config . host || ! api . config . port || ! api . config . ns ) {
310
310
const message = "'host', 'port' and 'ns' must be specified." ;
311
311
outputChannel . appendError ( message ) ;
312
312
panel . text = `${ PANEL_LABEL } $(error)` ;
313
313
panel . tooltip = `ERROR - ${ message } ` ;
314
- disableConnection ( configName ) ;
314
+ if ( ! api . externalServer ) {
315
+ await setConnectionState ( configName , false ) ;
316
+ }
315
317
return ;
316
318
}
317
319
checkingConnection = true ;
320
+
321
+ // What we do when api.serverInfo call succeeds
322
+ const gotServerInfo = async ( info ) => {
323
+ panel . text = api . connInfo ;
324
+ panel . tooltip = `Connected${ pathPrefix ? " to " + pathPrefix : "" } as ${ username } ` ;
325
+ const hasHS = info . result . content . features . find ( ( el ) => el . name === "HEALTHSHARE" && el . enabled ) !== undefined ;
326
+ reporter &&
327
+ reporter . sendTelemetryEvent ( "connected" , {
328
+ serverVersion : info . result . content . version ,
329
+ healthshare : hasHS ? "yes" : "no" ,
330
+ } ) ;
331
+
332
+ // Update CSP web app cache if required
333
+ const key = (
334
+ api . config . serverName && api . config . serverName != ""
335
+ ? `${ api . config . serverName } :${ api . config . ns } `
336
+ : `${ api . config . host } :${ api . config . port } ${ api . config . pathPrefix } :${ api . config . ns } `
337
+ ) . toLowerCase ( ) ;
338
+ if ( ! cspApps . has ( key ) ) {
339
+ cspApps . set ( key , await api . getCSPApps ( ) . then ( ( data ) => data . result . content || [ ] ) ) ;
340
+ }
341
+ if ( ! api . externalServer ) {
342
+ await setConnectionState ( configName , true ) ;
343
+ }
344
+ return ;
345
+ } ;
346
+
347
+ // Do the check
318
348
return api
319
349
. serverInfo ( )
320
- . then ( async ( info ) => {
321
- panel . text = api . connInfo ;
322
- panel . tooltip = `Connected${ pathPrefix ? " to " + pathPrefix : "" } as ${ username } ` ;
323
- const hasHS = info . result . content . features . find ( ( el ) => el . name === "HEALTHSHARE" && el . enabled ) !== undefined ;
324
- reporter &&
325
- reporter . sendTelemetryEvent ( "connected" , {
326
- serverVersion : info . result . content . version ,
327
- healthshare : hasHS ? "yes" : "no" ,
328
- } ) ;
329
- // Update CSP web app cache if required
330
- const key = (
331
- api . config . serverName && api . config . serverName != ""
332
- ? `${ api . config . serverName } :${ api . config . ns } `
333
- : `${ api . config . host } :${ api . config . port } ${ api . config . pathPrefix } :${ api . config . ns } `
334
- ) . toLowerCase ( ) ;
335
- if ( ! cspApps . has ( key ) ) {
336
- cspApps . set ( key , await api . getCSPApps ( ) . then ( ( data ) => data . result . content || [ ] ) ) ;
337
- }
338
- return ;
339
- } )
340
- . catch ( ( error ) => {
350
+ . then ( gotServerInfo )
351
+ . catch ( async ( error ) => {
341
352
let message = error . message ;
342
353
let errorMessage ;
343
354
if ( error . statusCode === 401 ) {
344
- setTimeout ( ( ) => {
345
- const username = api . config . username ;
346
- if ( username === "" ) {
347
- vscode . window . showErrorMessage ( `Anonymous access rejected by ${ connInfo } .` ) ;
348
- if ( ! api . externalServer ) {
349
- vscode . window . showErrorMessage ( "Connection has been disabled." ) ;
350
- disableConnection ( configName ) ;
351
- }
352
- } else {
353
- InputBoxManager . showInputBox (
354
- {
355
+ let success = false ;
356
+ message = "Not Authorized." ;
357
+ errorMessage = `Authorization error: Check your credentials in Settings, and that you have sufficient privileges on the /api/atelier web application on ${ connInfo } ` ;
358
+ const username = api . config . username ;
359
+ if ( username === "" ) {
360
+ vscode . window . showErrorMessage ( `Anonymous access rejected by ${ connInfo } .` ) ;
361
+ if ( ! api . externalServer ) {
362
+ vscode . window . showErrorMessage ( "Connection has been disabled." ) ;
363
+ await setConnectionState ( configName , false ) ;
364
+ }
365
+ } else {
366
+ success = await new Promise < boolean > ( ( resolve ) => {
367
+ vscode . window
368
+ . showInputBox ( {
355
369
password : true ,
356
370
placeHolder : `Not Authorized. Enter password to connect as user '${ username } ' to ${ connInfo } ` ,
357
371
prompt : ! api . externalServer ? "If no password is entered the connection will be disabled." : "" ,
358
372
ignoreFocusOut : true ,
359
- } ,
360
- async ( password ) => {
361
- if ( password ) {
362
- workspaceState . update ( configName + ":password" , password ) ;
363
- _onDidChangeConnection . fire ( ) ;
364
- await checkConnection ( false , uri ) ;
365
- } else if ( ! api . externalServer ) {
366
- disableConnection ( configName ) ;
373
+ } )
374
+ . then (
375
+ async ( password ) => {
376
+ if ( password ) {
377
+ await workspaceState . update ( configName + ":password" , password ) ;
378
+ resolve (
379
+ api
380
+ . serverInfo ( )
381
+ . then ( async ( info ) : Promise < boolean > => {
382
+ await gotServerInfo ( info ) ;
383
+ _onDidChangeConnection . fire ( ) ;
384
+ return true ;
385
+ } )
386
+ . catch ( async ( error ) => {
387
+ console . log ( `Second connect failed: ${ error } ` ) ;
388
+ await setConnectionState ( configName , false ) ;
389
+ await workspaceState . update ( configName + ":password" , undefined ) ;
390
+ return false ;
391
+ } )
392
+ . finally ( ( ) => {
393
+ checkingConnection = false ;
394
+ } )
395
+ ) ;
396
+ } else if ( ! api . externalServer ) {
397
+ await setConnectionState ( configName , false ) ;
398
+ }
399
+ console . log ( `Finished prompting for password` ) ;
400
+ resolve ( false ) ;
401
+ } ,
402
+ ( reason ) => {
403
+ console . log ( `showInputBox for password dismissed: ${ reason } ` ) ;
367
404
}
368
- } ,
369
- connInfo
370
- ) ;
405
+ ) ;
406
+ } ) ;
407
+ if ( success ) {
408
+ return ;
371
409
}
372
- } , 1000 ) ;
373
- message = "Not Authorized." ;
374
- errorMessage = `Authorization error: Check your credentials in Settings, and that you have sufficient privileges on the /api/atelier web application on ${ connInfo } ` ;
410
+ }
375
411
} else {
376
412
errorMessage = `${ message } \nCheck your server details in Settings (${ connInfo } ).` ;
377
413
}
@@ -395,16 +431,16 @@ export async function checkConnection(clearCookies = false, uri?: vscode.Uri): P
395
431
} ) ;
396
432
}
397
433
398
- // Set objectscript.conn.active = false at WorkspaceFolder level if objectscript.conn is defined there,
399
- // else set it false at Workspace level
400
- function disableConnection ( configName : string ) {
434
+ // Set objectscript.conn.active at WorkspaceFolder level if objectscript.conn is defined there,
435
+ // else set it at Workspace level
436
+ function setConnectionState ( configName : string , active : boolean ) {
401
437
const connConfig : vscode . WorkspaceConfiguration = config ( "" , configName ) ;
402
438
const target : vscode . ConfigurationTarget = connConfig . inspect ( "conn" ) . workspaceFolderValue
403
439
? vscode . ConfigurationTarget . WorkspaceFolder
404
440
: vscode . ConfigurationTarget . Workspace ;
405
441
const targetConfig : any =
406
442
connConfig . inspect ( "conn" ) . workspaceFolderValue || connConfig . inspect ( "conn" ) . workspaceValue ;
407
- return connConfig . update ( "conn" , { ...targetConfig , active : false } , target ) ;
443
+ return connConfig . update ( "conn" , { ...targetConfig , active } , target ) ;
408
444
}
409
445
410
446
// Promise to return the API of the servermanager
@@ -521,7 +557,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
521
557
serverManagerApi = await serverManager ( ) ;
522
558
523
559
documentContentProvider = new DocumentContentProvider ( ) ;
524
- xmlContentProvider = new XmlContentProvider ( ) ;
525
560
fileSystemProvider = new FileSystemProvider ( ) ;
526
561
527
562
explorerProvider = new ObjectScriptExplorerProvider ( ) ;
@@ -555,17 +590,27 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
555
590
vscode . workspace . workspaceFolders ?. map ( ( workspaceFolder ) => {
556
591
const uri = workspaceFolder . uri ;
557
592
const { configName } = connectionTarget ( uri ) ;
558
- toCheck . set ( configName , uri ) ;
593
+ const serverName = uri . scheme === "file" ? config ( "conn" , configName ) . server : configName ;
594
+ toCheck . set ( serverName , uri ) ;
559
595
} ) ;
560
596
for await ( const oneToCheck of toCheck ) {
561
- const configName = oneToCheck [ 0 ] ;
597
+ const serverName = oneToCheck [ 0 ] ;
562
598
const uri = oneToCheck [ 1 ] ;
563
- const serverName = uri . scheme === "file" ? config ( "conn" , configName ) . server : configName ;
564
- await resolveConnectionSpec ( serverName ) ;
565
- // Ignore any failure
566
- checkConnection ( true , uri ) . finally ( ) ;
599
+ try {
600
+ try {
601
+ await resolveConnectionSpec ( serverName ) ;
602
+ } finally {
603
+ await checkConnection ( true , uri ) ;
604
+ }
605
+ } catch ( _ ) {
606
+ // Ignore any failure
607
+ continue ;
608
+ }
567
609
}
568
610
611
+ // This constructor instantiates an AtelierAPI object, so needs to happen after resolving and checking connections above
612
+ xmlContentProvider = new XmlContentProvider ( ) ;
613
+
569
614
const documentSelector = ( ...list ) =>
570
615
[ "file" , ...schemas ] . reduce ( ( acc , scheme ) => acc . concat ( list . map ( ( language ) => ( { scheme, language } ) ) ) , [ ] ) ;
571
616
0 commit comments