1
1
import axios from "axios"
2
2
import { getAuthenticatedUser , getWorkspaces , updateWorkspaceVersion } from "coder/site/src/api/api"
3
- import { Workspace } from "coder/site/src/api/typesGenerated"
3
+ import { Workspace , WorkspaceAgent } from "coder/site/src/api/typesGenerated"
4
4
import * as vscode from "vscode"
5
- import { extractAgentsAndFolderPath } from "./api-helper"
5
+ import { extractAgents } from "./api-helper"
6
6
import { Remote } from "./remote"
7
7
import { Storage } from "./storage"
8
- import { WorkspaceTreeItem } from "./workspacesProvider"
8
+ import { OpenableTreeItem } from "./workspacesProvider"
9
9
10
10
export class Commands {
11
11
public constructor ( private readonly vscodeProposed : typeof vscode , private readonly storage : Storage ) { }
@@ -118,7 +118,7 @@ export class Commands {
118
118
await vscode . commands . executeCommand ( "vscode.open" , uri )
119
119
}
120
120
121
- public async navigateToWorkspace ( workspace : WorkspaceTreeItem ) {
121
+ public async navigateToWorkspace ( workspace : OpenableTreeItem ) {
122
122
if ( workspace ) {
123
123
const uri = this . storage . getURL ( ) + `/@${ workspace . workspaceOwner } /${ workspace . workspaceName } `
124
124
await vscode . commands . executeCommand ( "vscode.open" , uri )
@@ -130,7 +130,7 @@ export class Commands {
130
130
}
131
131
}
132
132
133
- public async navigateToWorkspaceSettings ( workspace : WorkspaceTreeItem ) {
133
+ public async navigateToWorkspaceSettings ( workspace : OpenableTreeItem ) {
134
134
if ( workspace ) {
135
135
const uri = this . storage . getURL ( ) + `/@${ workspace . workspaceOwner } /${ workspace . workspaceName } /settings`
136
136
await vscode . commands . executeCommand ( "vscode.open" , uri )
@@ -143,9 +143,21 @@ export class Commands {
143
143
}
144
144
}
145
145
146
+ public async openFromSidebar ( treeItem : OpenableTreeItem ) {
147
+ if ( treeItem ) {
148
+ await openWorkspace (
149
+ treeItem . workspaceOwner ,
150
+ treeItem . workspaceName ,
151
+ treeItem . workspaceAgent ,
152
+ treeItem . workspaceFolderPath ,
153
+ )
154
+ }
155
+ }
156
+
146
157
public async open ( ...args : unknown [ ] ) : Promise < void > {
147
158
let workspaceOwner : string
148
159
let workspaceName : string
160
+ let workspaceAgent : string | undefined
149
161
let folderPath : string | undefined
150
162
151
163
if ( args . length === 0 ) {
@@ -200,83 +212,61 @@ export class Commands {
200
212
workspaceOwner = workspace . owner_name
201
213
workspaceName = workspace . name
202
214
203
- const [ , folderPathExtracted ] = extractAgentsAndFolderPath ( workspace )
204
- folderPath = folderPathExtracted
205
- } else if ( args . length === 2 ) {
206
- // opening a workspace from the sidebar
207
- const workspaceTreeItem = args [ 0 ] as WorkspaceTreeItem
208
- workspaceOwner = workspaceTreeItem . workspaceOwner
209
- workspaceName = workspaceTreeItem . workspaceName
210
- folderPath = workspaceTreeItem . workspaceFolderPath
211
- } else {
212
- workspaceOwner = args [ 0 ] as string
213
- workspaceName = args [ 1 ] as string
214
- // workspaceAgent is reserved for args[2], but multiple agents aren't supported yet.
215
- folderPath = args [ 3 ] as string | undefined
216
- }
217
-
218
- // A workspace can have multiple agents, but that's handled
219
- // when opening a workspace unless explicitly specified.
220
- const remoteAuthority = `ssh-remote+${ Remote . Prefix } ${ workspaceOwner } --${ workspaceName } `
215
+ const agents = extractAgents ( workspace )
221
216
222
- let newWindow = true
223
- // Open in the existing window if no workspaces are open.
224
- if ( ! vscode . workspace . workspaceFolders ?. length ) {
225
- newWindow = false
226
- }
217
+ if ( agents . length === 1 ) {
218
+ folderPath = agents [ 0 ] . expanded_directory
219
+ workspaceAgent = agents [ 0 ] . name
220
+ } else if ( agents . length > 0 ) {
221
+ const agentQuickPick = vscode . window . createQuickPick ( )
222
+ agentQuickPick . title = `Select an agent`
227
223
228
- // If a folder isn't specified, we can try to open a recently opened folder.
229
- if ( ! folderPath ) {
230
- const output : {
231
- workspaces : { folderUri : vscode . Uri ; remoteAuthority : string } [ ]
232
- } = await vscode . commands . executeCommand ( "_workbench.getRecentlyOpened" )
233
- const opened = output . workspaces . filter (
234
- // Filter out `/` since that's added below.
235
- ( opened ) => opened . folderUri ?. authority === remoteAuthority ,
236
- )
237
- if ( opened . length > 0 ) {
238
- let selected : ( typeof opened ) [ 0 ]
224
+ agentQuickPick . busy = true
225
+ const lastAgents = agents
226
+ const agentItems : vscode . QuickPickItem [ ] = agents . map ( ( agent ) => {
227
+ let icon = "$(debug-start)"
228
+ if ( agent . status !== "connected" ) {
229
+ icon = "$(debug-stop)"
230
+ }
231
+ return {
232
+ alwaysShow : true ,
233
+ label : `${ icon } ${ agent . name } ` ,
234
+ detail : `${ agent . name } • Status: ${ agent . status } ` ,
235
+ }
236
+ } )
237
+ agentQuickPick . items = agentItems
238
+ agentQuickPick . busy = false
239
+ agentQuickPick . show ( )
239
240
240
- if ( opened . length > 1 ) {
241
- const items : vscode . QuickPickItem [ ] = opened . map ( ( folder ) : vscode . QuickPickItem => {
242
- return {
243
- label : folder . folderUri . path ,
244
- }
241
+ const agent = await new Promise < WorkspaceAgent | undefined > ( ( resolve ) => {
242
+ agentQuickPick . onDidHide ( ( ) => {
243
+ resolve ( undefined )
245
244
} )
246
- const item = await vscode . window . showQuickPick ( items , {
247
- title : "Select a recently opened folder" ,
245
+ agentQuickPick . onDidChangeSelection ( ( selected ) => {
246
+ if ( selected . length < 1 ) {
247
+ return resolve ( undefined )
248
+ }
249
+ const agent = lastAgents [ agentQuickPick . items . indexOf ( selected [ 0 ] ) ]
250
+ resolve ( agent )
248
251
} )
249
- if ( ! item ) {
250
- return
251
- }
252
- selected = opened [ items . indexOf ( item ) ]
252
+ } )
253
+
254
+ if ( agent ) {
255
+ folderPath = agent . expanded_directory
256
+ workspaceAgent = agent . name
253
257
} else {
254
- selected = opened [ 0 ]
258
+ folderPath = ""
259
+ workspaceAgent = ""
255
260
}
256
-
257
- folderPath = selected . folderUri . path
258
261
}
262
+ } else {
263
+ workspaceOwner = args [ 0 ] as string
264
+ workspaceName = args [ 1 ] as string
265
+ // workspaceAgent is reserved for args[2], but multiple agents aren't supported yet.
266
+ folderPath = args [ 3 ] as string | undefined
259
267
}
260
268
261
- if ( folderPath ) {
262
- await vscode . commands . executeCommand (
263
- "vscode.openFolder" ,
264
- vscode . Uri . from ( {
265
- scheme : "vscode-remote" ,
266
- authority : remoteAuthority ,
267
- path : folderPath ,
268
- } ) ,
269
- // Open this in a new window!
270
- newWindow ,
271
- )
272
- return
273
- }
274
-
275
- // This opens the workspace without an active folder opened.
276
- await vscode . commands . executeCommand ( "vscode.newWindow" , {
277
- remoteAuthority : remoteAuthority ,
278
- reuseWindow : ! newWindow ,
279
- } )
269
+ await openWorkspace ( workspaceOwner , workspaceName , workspaceAgent , folderPath )
280
270
}
281
271
282
272
public async updateWorkspace ( ) : Promise < void > {
@@ -297,3 +287,76 @@ export class Commands {
297
287
}
298
288
}
299
289
}
290
+
291
+ async function openWorkspace (
292
+ workspaceOwner : string ,
293
+ workspaceName : string ,
294
+ workspaceAgent : string | undefined ,
295
+ folderPath : string | undefined ,
296
+ ) {
297
+ // A workspace can have multiple agents, but that's handled
298
+ // when opening a workspace unless explicitly specified.
299
+ let remoteAuthority = `ssh-remote+${ Remote . Prefix } ${ workspaceOwner } --${ workspaceName } `
300
+ if ( workspaceAgent ) {
301
+ remoteAuthority += `--${ workspaceAgent } `
302
+ }
303
+
304
+ let newWindow = true
305
+ // Open in the existing window if no workspaces are open.
306
+ if ( ! vscode . workspace . workspaceFolders ?. length ) {
307
+ newWindow = false
308
+ }
309
+
310
+ // If a folder isn't specified, we can try to open a recently opened folder.
311
+ if ( ! folderPath ) {
312
+ const output : {
313
+ workspaces : { folderUri : vscode . Uri ; remoteAuthority : string } [ ]
314
+ } = await vscode . commands . executeCommand ( "_workbench.getRecentlyOpened" )
315
+ const opened = output . workspaces . filter (
316
+ // Filter out `/` since that's added below.
317
+ ( opened ) => opened . folderUri ?. authority === remoteAuthority ,
318
+ )
319
+ if ( opened . length > 0 ) {
320
+ let selected : ( typeof opened ) [ 0 ]
321
+
322
+ if ( opened . length > 1 ) {
323
+ const items : vscode . QuickPickItem [ ] = opened . map ( ( folder ) : vscode . QuickPickItem => {
324
+ return {
325
+ label : folder . folderUri . path ,
326
+ }
327
+ } )
328
+ const item = await vscode . window . showQuickPick ( items , {
329
+ title : "Select a recently opened folder" ,
330
+ } )
331
+ if ( ! item ) {
332
+ return
333
+ }
334
+ selected = opened [ items . indexOf ( item ) ]
335
+ } else {
336
+ selected = opened [ 0 ]
337
+ }
338
+
339
+ folderPath = selected . folderUri . path
340
+ }
341
+ }
342
+
343
+ if ( folderPath ) {
344
+ await vscode . commands . executeCommand (
345
+ "vscode.openFolder" ,
346
+ vscode . Uri . from ( {
347
+ scheme : "vscode-remote" ,
348
+ authority : remoteAuthority ,
349
+ path : folderPath ,
350
+ } ) ,
351
+ // Open this in a new window!
352
+ newWindow ,
353
+ )
354
+ return
355
+ }
356
+
357
+ // This opens the workspace without an active folder opened.
358
+ await vscode . commands . executeCommand ( "vscode.newWindow" , {
359
+ remoteAuthority : remoteAuthority ,
360
+ reuseWindow : ! newWindow ,
361
+ } )
362
+ }
0 commit comments