@@ -13,38 +13,40 @@ export enum WorkspaceQuery {
1313
1414export class WorkspaceProvider implements vscode . TreeDataProvider < vscode . TreeItem > {
1515 private workspaces : WorkspaceTreeItem [ ] = [ ]
16- private agentMetadata : Record < WorkspaceAgent [ "id" ] , AgentMetadataEvent [ ] > = { }
16+ private agentWatchers : Record < WorkspaceAgent [ "id" ] , { dispose : ( ) => void ; metadata ?: AgentMetadataEvent [ ] } > = { }
1717
1818 constructor ( private readonly getWorkspacesQuery : WorkspaceQuery , private readonly storage : Storage ) {
19- getWorkspaces ( { q : this . getWorkspacesQuery } )
20- . then ( ( workspaces ) => {
21- const workspacesTreeItem : WorkspaceTreeItem [ ] = [ ]
22- workspaces . workspaces . forEach ( ( workspace ) => {
23- const showMetadata = this . getWorkspacesQuery === WorkspaceQuery . Mine
24- if ( showMetadata ) {
25- const agents = extractAgents ( workspace )
26- agents . forEach ( ( agent ) => this . monitorMetadata ( agent . id ) ) // monitor metadata for all agents
27- }
28- const treeItem = new WorkspaceTreeItem (
29- workspace ,
30- this . getWorkspacesQuery === WorkspaceQuery . All ,
31- showMetadata ,
32- )
33- workspacesTreeItem . push ( treeItem )
34- } )
35- return workspacesTreeItem
36- } )
37- . then ( ( workspaces ) => {
38- this . workspaces = workspaces
39- this . refresh ( )
19+ this . fetchAndRefresh ( )
20+ }
21+
22+ // fetchAndRefrehsh fetches new workspaces then re-renders the entire tree.
23+ async fetchAndRefresh ( ) {
24+ const token = await this . storage . getSessionToken ( )
25+ const workspacesTreeItem : WorkspaceTreeItem [ ] = [ ]
26+ Object . values ( this . agentWatchers ) . forEach ( ( watcher ) => watcher . dispose ( ) )
27+ // If the URL is set then we are logged in.
28+ if ( this . storage . getURL ( ) ) {
29+ const resp = await getWorkspaces ( { q : this . getWorkspacesQuery } )
30+ resp . workspaces . forEach ( ( workspace ) => {
31+ const showMetadata = this . getWorkspacesQuery === WorkspaceQuery . Mine
32+ if ( showMetadata && token ) {
33+ const agents = extractAgents ( workspace )
34+ agents . forEach ( ( agent ) => this . monitorMetadata ( agent . id , token ) ) // monitor metadata for all agents
35+ }
36+ const treeItem = new WorkspaceTreeItem ( workspace , this . getWorkspacesQuery === WorkspaceQuery . All , showMetadata )
37+ workspacesTreeItem . push ( treeItem )
4038 } )
39+ }
40+ this . workspaces = workspacesTreeItem
41+ this . refresh ( )
4142 }
4243
4344 private _onDidChangeTreeData : vscode . EventEmitter < vscode . TreeItem | undefined | null | void > =
4445 new vscode . EventEmitter < vscode . TreeItem | undefined | null | void > ( )
4546 readonly onDidChangeTreeData : vscode . Event < vscode . TreeItem | undefined | null | void > =
4647 this . _onDidChangeTreeData . event
4748
49+ // refresh causes the tree to re-render. It does not fetch fresh workspaces.
4850 refresh ( item : vscode . TreeItem | undefined | null | void ) : void {
4951 this . _onDidChangeTreeData . fire ( item )
5052 }
@@ -62,7 +64,7 @@ export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeIte
6264 )
6365 return Promise . resolve ( agentTreeItems )
6466 } else if ( element instanceof AgentTreeItem ) {
65- const savedMetadata = this . agentMetadata [ element . agent . id ] || [ ]
67+ const savedMetadata = this . agentWatchers [ element . agent . id ] ?. metadata || [ ]
6668 return Promise . resolve ( savedMetadata . map ( ( metadata ) => new AgentMetadataTreeItem ( metadata ) ) )
6769 }
6870
@@ -71,30 +73,39 @@ export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeIte
7173 return Promise . resolve ( this . workspaces )
7274 }
7375
74- async monitorMetadata ( agentId : WorkspaceAgent [ "id" ] ) : Promise < void > {
76+ // monitorMetadata opens an SSE endpoint to monitor metadata on the specified
77+ // agent and registers a disposer that can be used to stop the watch.
78+ monitorMetadata ( agentId : WorkspaceAgent [ "id" ] , token : string ) : void {
7579 const agentMetadataURL = new URL ( `${ this . storage . getURL ( ) } /api/v2/workspaceagents/${ agentId } /watch-metadata` )
7680 const agentMetadataEventSource = new EventSource ( agentMetadataURL . toString ( ) , {
7781 headers : {
78- "Coder-Session-Token" : await this . storage . getSessionToken ( ) ,
82+ "Coder-Session-Token" : token ,
7983 } ,
8084 } )
8185
86+ this . agentWatchers [ agentId ] = {
87+ dispose : ( ) => {
88+ delete this . agentWatchers [ agentId ]
89+ agentMetadataEventSource . close ( )
90+ } ,
91+ }
92+
8293 agentMetadataEventSource . addEventListener ( "data" , ( event ) => {
8394 try {
8495 const dataEvent = JSON . parse ( event . data )
8596 const agentMetadata = AgentMetadataEventSchemaArray . parse ( dataEvent )
8697
8798 if ( agentMetadata . length === 0 ) {
88- agentMetadataEventSource . close ( )
99+ this . agentWatchers [ agentId ] . dispose ( )
89100 }
90101
91- const savedMetadata = this . agentMetadata [ agentId ]
102+ const savedMetadata = this . agentWatchers [ agentId ] . metadata
92103 if ( JSON . stringify ( savedMetadata ) !== JSON . stringify ( agentMetadata ) ) {
93- this . agentMetadata [ agentId ] = agentMetadata // overwrite existing metadata
104+ this . agentWatchers [ agentId ] . metadata = agentMetadata // overwrite existing metadata
94105 this . refresh ( )
95106 }
96107 } catch ( error ) {
97- agentMetadataEventSource . close ( )
108+ this . agentWatchers [ agentId ] . dispose ( )
98109 }
99110 } )
100111 }
0 commit comments