11import axios from "axios"
22import { 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"
44import * as vscode from "vscode"
5- import { extractAgentsAndFolderPath } from "./api-helper"
5+ import { extractAgents } from "./api-helper"
66import { Remote } from "./remote"
77import { Storage } from "./storage"
88import { WorkspaceTreeItem } from "./workspacesProvider"
@@ -143,9 +143,21 @@ export class Commands {
143143 }
144144 }
145145
146+ public async openFromSidebar ( treeItem : WorkspaceTreeItem ) {
147+ if ( treeItem ) {
148+ await openWorkspace (
149+ treeItem . workspaceOwner ,
150+ treeItem . workspaceName ,
151+ treeItem . workspaceAgent ,
152+ treeItem . workspaceFolderPath ,
153+ )
154+ }
155+ }
156+
146157 public async open ( ...args : unknown [ ] ) : Promise < void > {
147158 let workspaceOwner : string
148159 let workspaceName : string
160+ let workspaceAgent : string | undefined
149161 let folderPath : string | undefined
150162
151163 if ( args . length === 0 ) {
@@ -200,83 +212,61 @@ export class Commands {
200212 workspaceOwner = workspace . owner_name
201213 workspaceName = workspace . name
202214
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 )
221216
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 {
221+ const agentQuickPick = vscode . window . createQuickPick ( )
222+ agentQuickPick . title = `Select an agent`
227223
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 ( )
239240
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 )
245244 } )
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 )
248251 } )
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
253257 } else {
254- selected = opened [ 0 ]
258+ folderPath = ""
259+ workspaceAgent = ""
255260 }
256-
257- folderPath = selected . folderUri . path
258261 }
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
259267 }
260268
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 )
280270 }
281271
282272 public async updateWorkspace ( ) : Promise < void > {
@@ -297,3 +287,76 @@ export class Commands {
297287 }
298288 }
299289}
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