@@ -2,8 +2,9 @@ import * as vscode from "vscode";
2
2
import { getServerNames } from "../api/getServerNames" ;
3
3
import { getServerSpec } from "../api/getServerSpec" ;
4
4
import { getServerSummary } from "../api/getServerSummary" ;
5
- import { IServerName } from "@intersystems-community/intersystems-servermanager" ;
5
+ import { IServerName , IServerSpec } from "@intersystems-community/intersystems-servermanager" ;
6
6
import { makeRESTRequest } from "../makeRESTRequest" ;
7
+ import { OBJECTSCRIPT_EXTENSIONID } from "../extension" ;
7
8
8
9
const SETTINGS_VERSION = "v1" ;
9
10
@@ -271,10 +272,12 @@ function allServers(treeItem: SMTreeItem, params?: any): ServerTreeItem[] {
271
272
return children ;
272
273
}
273
274
274
- function currentServers ( element : SMTreeItem , params ?: any ) : ServerTreeItem [ ] {
275
+ async function currentServers ( element : SMTreeItem , params ?: any ) : Promise < ServerTreeItem [ ] > {
275
276
const children = new Map < string , ServerTreeItem > ( ) ;
277
+ const dockerLocalPorts = new Map < number , string > ( ) ;
276
278
277
- vscode . workspace . workspaceFolders ?. map ( ( folder ) => {
279
+ const workspaceFolders = vscode . workspace . workspaceFolders || [ ] ;
280
+ await Promise . all ( workspaceFolders . map ( async ( folder ) => {
278
281
const serverName = folder . uri . authority . split ( ":" ) [ 0 ] ;
279
282
if ( [ "isfs" , "isfs-readonly" ] . includes ( folder . uri . scheme ) ) {
280
283
const serverSummary = getServerSummary ( serverName ) ;
@@ -284,10 +287,25 @@ function currentServers(element: SMTreeItem, params?: any): ServerTreeItem[] {
284
287
new ServerTreeItem ( { parent : element , label : serverName , id : serverName } , serverSummary ) ,
285
288
) ;
286
289
}
290
+ return ;
287
291
}
288
292
const conn = vscode . workspace . getConfiguration ( "objectscript.conn" , folder ) ;
289
293
const connServer = conn . get < string > ( "server" ) ;
290
- if ( connServer ) {
294
+ if ( conn . get ( "docker-compose" ) ) {
295
+ const objectScriptExtension = vscode . extensions . getExtension ( OBJECTSCRIPT_EXTENSIONID ) ;
296
+ if ( objectScriptExtension ) {
297
+ if ( ! objectScriptExtension . isActive ) {
298
+ await objectScriptExtension . activate ( ) ;
299
+ }
300
+ if ( objectScriptExtension . isActive && objectScriptExtension . exports ?. asyncServerForUri ) {
301
+ const server = await objectScriptExtension . exports . asyncServerForUri ( folder . uri ) ;
302
+ if ( server && server . host === "localhost" && server . port > 0 && ! dockerLocalPorts . has ( server . port ) ) {
303
+ dockerLocalPorts . set ( server . port , folder . name ) ;
304
+ }
305
+ }
306
+ }
307
+ }
308
+ else if ( connServer ) {
291
309
const serverSummary = getServerSummary ( connServer ) ;
292
310
if ( serverSummary ) {
293
311
children . set (
@@ -296,7 +314,18 @@ function currentServers(element: SMTreeItem, params?: any): ServerTreeItem[] {
296
314
) ;
297
315
}
298
316
}
299
- } ) ;
317
+
318
+ } ) ) ;
319
+
320
+ dockerLocalPorts . forEach ( ( name , port ) => {
321
+ if ( ! children . has ( name ) ) {
322
+ const serverSummary : IServerName = { name, description : `Docker service bound to local port ${ port } for folder '${ name } '` , detail : `http://localhost:${ port } /` } ;
323
+ children . set (
324
+ name ,
325
+ new ServerTreeItem ( { parent : element , label : `docker:${ port } ` , id : name } , serverSummary ) ,
326
+ ) ;
327
+ }
328
+ } )
300
329
301
330
return Array . from ( children . values ( ) ) . sort ( ( a , b ) => a . name < b . name ? - 1 : a . name > b . name ? 1 : 0 ) ;
302
331
}
@@ -347,7 +376,7 @@ export class ServerTreeItem extends SMTreeItem {
347
376
super ( {
348
377
getChildren : serverFeatures ,
349
378
id : parentFolderId + ":" + serverSummary . name ,
350
- label : serverSummary . name ,
379
+ label : element . label ? element . label : serverSummary . name ,
351
380
params : { serverSummary } ,
352
381
parent : element . parent ,
353
382
tooltip : new vscode . MarkdownString ( wrappedDetail ) . appendMarkdown ( escapedDescription ? `\n\n*${ escapedDescription } *` : "" ) ,
@@ -377,12 +406,12 @@ async function serverFeatures(element: ServerTreeItem, params?: any): Promise<Fe
377
406
const children : FeatureTreeItem [ ] = [ ] ;
378
407
379
408
if ( params ?. serverSummary ) {
380
- const name = params . serverSummary . name ;
381
- const serverSpec = await getServerSpec ( name ) ;
409
+ let serverSpec = await specFromServerSummary ( params . serverSummary ) ;
382
410
if ( ! serverSpec ) {
383
411
return undefined ;
384
412
}
385
413
414
+ const name = serverSpec . name ;
386
415
let response = await makeRESTRequest ( "HEAD" , serverSpec ) ;
387
416
if ( response ?. status === 401 ) {
388
417
// Authentication error, so retry in case first attempt cleared a no-longer-valid stored password
@@ -392,12 +421,21 @@ async function serverFeatures(element: ServerTreeItem, params?: any): Promise<Fe
392
421
if ( response ?. status !== 200 ) {
393
422
children . push ( new OfflineTreeItem ( { parent : element , label : name , id : name } , serverSpec . username || 'UnknownUser' ) ) ;
394
423
} else {
395
- children . push ( new NamespacesTreeItem ( { parent : element , label : name , id : name } , element . name , serverSpec . username || 'UnknownUser' ) ) ;
424
+ children . push ( new NamespacesTreeItem ( { parent : element , label : name , id : name } , element . name , serverSpec , serverSpec . username || 'UnknownUser' ) ) ;
396
425
}
397
426
}
398
427
return children ;
399
428
}
400
429
430
+ async function specFromServerSummary ( serverSummary : IServerName ) : Promise < IServerSpec | undefined > {
431
+ const { name, description, detail } = serverSummary ;
432
+ const dockerDetail = detail . match ( / ^ h t t p : \/ \/ l o c a l h o s t : ( \d + ) \/ $ / ) ;
433
+ if ( dockerDetail ) {
434
+ return { name, description, webServer : { scheme : "http" , host : "127.0.0.1" , port : parseInt ( dockerDetail [ 1 ] , 10 ) , pathPrefix : "" } } ;
435
+ }
436
+ return getServerSpec ( name ) ;
437
+ }
438
+
401
439
// tslint:disable-next-line: max-classes-per-file
402
440
export class FeatureTreeItem extends SMTreeItem {
403
441
}
@@ -428,14 +466,15 @@ export class NamespacesTreeItem extends FeatureTreeItem {
428
466
constructor (
429
467
element : ISMItem ,
430
468
serverName : string ,
469
+ serverSpec : IServerSpec ,
431
470
username : string
432
471
) {
433
472
const parentFolderId = element . parent ?. id || "" ;
434
473
super ( {
435
474
getChildren : serverNamespaces ,
436
475
id : parentFolderId + ":namespaces" ,
437
476
label : "Namespaces" ,
438
- params : { serverName } ,
477
+ params : { serverName, serverSpec } ,
439
478
parent : element . parent ,
440
479
tooltip : `Namespaces '${ username } ' can access` ,
441
480
} ) ;
@@ -457,7 +496,7 @@ async function serverNamespaces(element: ServerTreeItem, params?: any): Promise<
457
496
458
497
if ( params ?. serverName ) {
459
498
const name : string = params . serverName ;
460
- const serverSpec = await getServerSpec ( name ) ;
499
+ const serverSpec : IServerSpec | undefined = params . serverSpec ;
461
500
if ( ! serverSpec ) {
462
501
return undefined ;
463
502
}
@@ -468,7 +507,7 @@ async function serverNamespaces(element: ServerTreeItem, params?: any): Promise<
468
507
} else {
469
508
const serverApiVersion = response . data . result . content . api ;
470
509
response . data . result . content . namespaces . map ( ( namespace : string ) => {
471
- children . push ( new NamespaceTreeItem ( { parent : element , label : name , id : name } , namespace , name , serverApiVersion ) ) ;
510
+ children . push ( new NamespaceTreeItem ( { parent : element , label : name , id : name } , namespace , name , serverSpec , serverApiVersion ) ) ;
472
511
} ) ;
473
512
}
474
513
}
@@ -483,6 +522,7 @@ export class NamespaceTreeItem extends SMTreeItem {
483
522
element : ISMItem ,
484
523
name : string ,
485
524
serverName : string ,
525
+ serverSpec : IServerSpec ,
486
526
serverApiVersion : number
487
527
) {
488
528
const parentFolderId = element . parent ?. id || "" ;
@@ -493,7 +533,7 @@ export class NamespaceTreeItem extends SMTreeItem {
493
533
parent : element . parent ,
494
534
tooltip : `${ name } on ${ serverName } ` ,
495
535
getChildren : namespaceFeatures ,
496
- params : { serverName, serverApiVersion }
536
+ params : { serverName, serverSpec , serverApiVersion }
497
537
} ) ;
498
538
this . name = name ;
499
539
this . contextValue = `${ serverApiVersion . toString ( ) } /${ name === "%SYS" ? "sysnamespace" : "namespace" } ` ;
@@ -510,8 +550,8 @@ export class NamespaceTreeItem extends SMTreeItem {
510
550
*/
511
551
async function namespaceFeatures ( element : NamespaceTreeItem , params ?: any ) : Promise < FeatureTreeItem [ ] | undefined > {
512
552
return [
513
- new ProjectsTreeItem ( { parent : element , id : element . name , label : element . name } , params . serverName , params . serverApiVersion ) ,
514
- new WebAppsTreeItem ( { parent : element , id : element . name , label : element . name } , params . serverName , params . serverApiVersion )
553
+ new ProjectsTreeItem ( { parent : element , id : element . name , label : element . name } , params . serverName , params . serverSpec , params . serverApiVersion ) ,
554
+ new WebAppsTreeItem ( { parent : element , id : element . name , label : element . name } , params . serverName , params . serverSpec , params . serverApiVersion )
515
555
] ;
516
556
}
517
557
@@ -520,6 +560,7 @@ export class ProjectsTreeItem extends FeatureTreeItem {
520
560
constructor (
521
561
element : ISMItem ,
522
562
serverName : string ,
563
+ serverSpec : IServerSpec ,
523
564
serverApiVersion : number
524
565
) {
525
566
const parentFolderId = element . parent ?. id || '' ;
@@ -529,7 +570,7 @@ export class ProjectsTreeItem extends FeatureTreeItem {
529
570
id : parentFolderId + ':projects' ,
530
571
tooltip : `Projects in this namespace` ,
531
572
getChildren : namespaceProjects ,
532
- params : { serverName, serverApiVersion, ns : element . label }
573
+ params : { serverName, serverSpec , serverApiVersion, ns : element . label }
533
574
} ) ;
534
575
this . name = 'Projects' ;
535
576
this . contextValue = serverApiVersion . toString ( ) + '/projects' ;
@@ -549,7 +590,7 @@ async function namespaceProjects(element: ProjectsTreeItem, params?: any): Promi
549
590
550
591
if ( params ?. serverName && params . ns ) {
551
592
const name : string = params . serverName ;
552
- const serverSpec = await getServerSpec ( name )
593
+ const serverSpec : IServerSpec | undefined = params . serverSpec ;
553
594
if ( ! serverSpec ) {
554
595
return undefined
555
596
}
@@ -607,6 +648,7 @@ export class WebAppsTreeItem extends FeatureTreeItem {
607
648
constructor (
608
649
element : ISMItem ,
609
650
serverName : string ,
651
+ serverSpec : IServerSpec ,
610
652
serverApiVersion : number
611
653
) {
612
654
const parentFolderId = element . parent ?. id || '' ;
@@ -616,7 +658,7 @@ export class WebAppsTreeItem extends FeatureTreeItem {
616
658
id : parentFolderId + ':webapps' ,
617
659
tooltip : `Web Applications in this namespace` ,
618
660
getChildren : namespaceWebApps ,
619
- params : { serverName, serverApiVersion, ns : element . label }
661
+ params : { serverName, serverSpec , serverApiVersion, ns : element . label }
620
662
} ) ;
621
663
this . name = 'Web Applications' ;
622
664
this . contextValue = serverApiVersion . toString ( ) + '/webapps' ;
@@ -636,7 +678,7 @@ async function namespaceWebApps(element: ProjectsTreeItem, params?: any): Promis
636
678
637
679
if ( params ?. serverName && params . ns ) {
638
680
const name : string = params . serverName ;
639
- const serverSpec = await getServerSpec ( name )
681
+ const serverSpec : IServerSpec | undefined = params . serverSpec ;
640
682
if ( ! serverSpec ) {
641
683
return undefined
642
684
}
0 commit comments