From a42f1ba74c670a05aab019a039a0da9aa37ed945 Mon Sep 17 00:00:00 2001 From: cheng Date: Mon, 13 Feb 2023 18:42:39 +0800 Subject: [PATCH 1/5] feat: multiple agent support --- src/commands.ts | 52 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 4db02219..fc41a65f 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -104,6 +104,7 @@ export class Commands { public async open(...args: string[]): Promise { let workspaceOwner: string let workspaceName: string + let workspaceAgent: string let folderPath: string | undefined if (args.length === 0) { @@ -158,24 +159,67 @@ export class Commands { workspaceOwner = workspace.owner_name workspaceName = workspace.name - // TODO: multiple agent support const agents = workspace.latest_build.resources.reduce((acc, resource) => { return acc.concat(resource.agents || []) }, [] as WorkspaceAgent[]) if (agents.length === 1) { folderPath = agents[0].expanded_directory - } + workspaceAgent = agents[0].name + }else{ + const agentQuickPick = vscode.window.createQuickPick() + let lastAgents: WorkspaceAgent[] + agentQuickPick.title = `Connect to a agent`; + + agentQuickPick.busy = true; + lastAgents = agents + const agentItems: vscode.QuickPickItem[] = agents.map((agent) => { + let icon = "$(debug-start)" + if (agent.status !== "connected") { + icon = "$(debug-stop)" + } + return { + alwaysShow: true, + label: `${icon} ${agent.name}`, + detail: `${agent.name} • Status: ${agent.status}`, + } + }) + agentQuickPick.items = agentItems + agentQuickPick.busy = false + agentQuickPick.show() + + const agent = await new Promise((resolve) => { + agentQuickPick.onDidHide(() => { + resolve(undefined) + }) + agentQuickPick.onDidChangeSelection((selected) => { + if (selected.length < 1) { + return resolve(undefined) + } + const agent = lastAgents[agentQuickPick.items.indexOf(selected[0])] + resolve(agent) + }) + }) + + if(agent != undefined){ + folderPath = agent.expanded_directory + workspaceAgent = agent.name + }else{ + folderPath = '' + workspaceAgent = '' + } + } + } else { workspaceOwner = args[0] workspaceName = args[1] - // workspaceAgent is reserved for args[2], but multiple agents aren't supported yet. + workspaceAgent = args[2] folderPath = args[3] } // A workspace can have multiple agents, but that's handled // when opening a workspace unless explicitly specified. - const remoteAuthority = `ssh-remote+${Remote.Prefix}${workspaceOwner}--${workspaceName}` + const remoteAuthority = `ssh-remote+${Remote.Prefix}${workspaceOwner}--${workspaceName}--${workspaceAgent}` let newWindow = true // Open in the existing window if no workspaces are open. From 5dba96c88a66a4f121c6fea1a5d20fe6aeecc4c8 Mon Sep 17 00:00:00 2001 From: ytcheng1 Date: Tue, 14 Feb 2023 09:04:05 +0800 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Kyle Carberry --- src/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands.ts b/src/commands.ts index fc41a65f..1894b097 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -169,7 +169,7 @@ export class Commands { }else{ const agentQuickPick = vscode.window.createQuickPick() let lastAgents: WorkspaceAgent[] - agentQuickPick.title = `Connect to a agent`; + agentQuickPick.title = `Select an agent`; agentQuickPick.busy = true; lastAgents = agents From 5100372418627ba7380bcf81db6c45b12bd4335e Mon Sep 17 00:00:00 2001 From: cheng Date: Tue, 14 Feb 2023 10:23:16 +0800 Subject: [PATCH 3/5] feat: multiple agent support --- src/commands.ts | 84 ++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 1894b097..98e2d196 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -166,50 +166,49 @@ export class Commands { if (agents.length === 1) { folderPath = agents[0].expanded_directory workspaceAgent = agents[0].name - }else{ - const agentQuickPick = vscode.window.createQuickPick() - let lastAgents: WorkspaceAgent[] - agentQuickPick.title = `Select an agent`; - - agentQuickPick.busy = true; - lastAgents = agents - const agentItems: vscode.QuickPickItem[] = agents.map((agent) => { - let icon = "$(debug-start)" - if (agent.status !== "connected") { - icon = "$(debug-stop)" - } - return { - alwaysShow: true, - label: `${icon} ${agent.name}`, - detail: `${agent.name} • Status: ${agent.status}`, - } + } else { + const agentQuickPick = vscode.window.createQuickPick() + let lastAgents: WorkspaceAgent[] + agentQuickPick.title = `Select an agent` + + agentQuickPick.busy = true + lastAgents = agents + const agentItems: vscode.QuickPickItem[] = agents.map((agent) => { + let icon = "$(debug-start)" + if (agent.status !== "connected") { + icon = "$(debug-stop)" + } + return { + alwaysShow: true, + label: `${icon} ${agent.name}`, + detail: `${agent.name} • Status: ${agent.status}`, + } + }) + agentQuickPick.items = agentItems + agentQuickPick.busy = false + agentQuickPick.show() + + const agent = await new Promise((resolve) => { + agentQuickPick.onDidHide(() => { + resolve(undefined) }) - agentQuickPick.items = agentItems - agentQuickPick.busy = false - agentQuickPick.show() - - const agent = await new Promise((resolve) => { - agentQuickPick.onDidHide(() => { - resolve(undefined) - }) - agentQuickPick.onDidChangeSelection((selected) => { - if (selected.length < 1) { - return resolve(undefined) - } - const agent = lastAgents[agentQuickPick.items.indexOf(selected[0])] - resolve(agent) - }) + agentQuickPick.onDidChangeSelection((selected) => { + if (selected.length < 1) { + return resolve(undefined) + } + const agent = lastAgents[agentQuickPick.items.indexOf(selected[0])] + resolve(agent) }) - - if(agent != undefined){ - folderPath = agent.expanded_directory - workspaceAgent = agent.name - }else{ - folderPath = '' - workspaceAgent = '' - } + }) + + if (agent != undefined) { + folderPath = agent.expanded_directory + workspaceAgent = agent.name + } else { + folderPath = "" + workspaceAgent = "" } - + } } else { workspaceOwner = args[0] workspaceName = args[1] @@ -219,7 +218,8 @@ export class Commands { // A workspace can have multiple agents, but that's handled // when opening a workspace unless explicitly specified. - const remoteAuthority = `ssh-remote+${Remote.Prefix}${workspaceOwner}--${workspaceName}--${workspaceAgent}` + let remoteAuthority = `ssh-remote+${Remote.Prefix}${workspaceOwner}--${workspaceName}` + if (workspaceAgent) remoteAuthority += `--${workspaceAgent}` let newWindow = true // Open in the existing window if no workspaces are open. From 6e121cc50f476db79aee0c6dea7af7b409529d56 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Wed, 26 Apr 2023 18:31:47 -0300 Subject: [PATCH 4/5] chore: lint --- src/commands.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 98e2d196..d8e0226b 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -168,11 +168,10 @@ export class Commands { workspaceAgent = agents[0].name } else { const agentQuickPick = vscode.window.createQuickPick() - let lastAgents: WorkspaceAgent[] agentQuickPick.title = `Select an agent` agentQuickPick.busy = true - lastAgents = agents + const lastAgents = agents const agentItems: vscode.QuickPickItem[] = agents.map((agent) => { let icon = "$(debug-start)" if (agent.status !== "connected") { @@ -201,7 +200,7 @@ export class Commands { }) }) - if (agent != undefined) { + if (agent) { folderPath = agent.expanded_directory workspaceAgent = agent.name } else { @@ -219,7 +218,9 @@ export class Commands { // A workspace can have multiple agents, but that's handled // when opening a workspace unless explicitly specified. let remoteAuthority = `ssh-remote+${Remote.Prefix}${workspaceOwner}--${workspaceName}` - if (workspaceAgent) remoteAuthority += `--${workspaceAgent}` + if (workspaceAgent) { + remoteAuthority += `--${workspaceAgent}` + } let newWindow = true // Open in the existing window if no workspaces are open. From e40d8761c4b32756e9b1fdddd9bc056355553fb4 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Fri, 28 Apr 2023 18:27:57 -0300 Subject: [PATCH 5/5] chore: updating sidebar to also support multiple agents --- package.json | 15 ++-- src/api-helper.ts | 11 +-- src/commands.ts | 156 +++++++++++++++++++++----------------- src/extension.ts | 1 + src/workspacesProvider.ts | 43 +++++++++-- 5 files changed, 136 insertions(+), 90 deletions(-) diff --git a/package.json b/package.json index 4b72504a..b3528d96 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,11 @@ "title": "Coder: Open Workspace", "icon": "$(play)" }, + { + "command": "coder.openFromSidebar", + "title": "Coder: Open Workspace", + "icon": "$(play)" + }, { "command": "coder.createWorkspace", "title": "Create Workspace", @@ -147,18 +152,18 @@ ], "view/item/context": [ { - "command": "coder.open", - "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces", + "command": "coder.openFromSidebar", + "when": "coder.authenticated && viewItem == coderWorkspaceSingleAgent || coder.authenticated && viewItem == coderAgent", "group": "inline" }, { "command": "coder.navigateToWorkspace", - "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces", + "when": "coder.authenticated && viewItem == coderWorkspaceSingleAgent || coder.authenticated && viewItem == coderWorkspaceMultipleAgents", "group": "inline" }, { "command": "coder.navigateToWorkspaceSettings", - "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces", + "when": "coder.authenticated && viewItem == coderWorkspaceSingleAgent || coder.authenticated && viewItem == coderWorkspaceMultipleAgents", "group": "inline" } ] @@ -223,4 +228,4 @@ "ws": "^8.11.0", "yaml": "^1.10.0" } -} \ No newline at end of file +} diff --git a/src/api-helper.ts b/src/api-helper.ts index 75c0af83..ea36a3b3 100644 --- a/src/api-helper.ts +++ b/src/api-helper.ts @@ -1,16 +1,9 @@ import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated" -export function extractAgentsAndFolderPath( - workspace: Workspace, -): [agents: WorkspaceAgent[], folderPath: string | undefined] { - // TODO: multiple agent support +export function extractAgents(workspace: Workspace): WorkspaceAgent[] { const agents = workspace.latest_build.resources.reduce((acc, resource) => { return acc.concat(resource.agents || []) }, [] as WorkspaceAgent[]) - let folderPath = undefined - if (agents.length === 1) { - folderPath = agents[0].expanded_directory - } - return [agents, folderPath] + return agents } diff --git a/src/commands.ts b/src/commands.ts index efca5528..9995e8bf 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -143,6 +143,17 @@ export class Commands { } } + public async openFromSidebar(treeItem: WorkspaceTreeItem) { + if (treeItem) { + await openWorkspace( + treeItem.workspaceOwner, + treeItem.workspaceName, + treeItem.workspaceAgent, + treeItem.workspaceFolderPath, + ) + } + } + public async open(...args: unknown[]): Promise { let workspaceOwner: string let workspaceName: string @@ -248,12 +259,6 @@ export class Commands { workspaceAgent = "" } } - } else if (args.length === 2) { - // opening a workspace from the sidebar - const workspaceTreeItem = args[0] as WorkspaceTreeItem - workspaceOwner = workspaceTreeItem.workspaceOwner - workspaceName = workspaceTreeItem.workspaceName - folderPath = workspaceTreeItem.workspaceFolderPath } else { workspaceOwner = args[0] as string workspaceName = args[1] as string @@ -261,71 +266,7 @@ export class Commands { folderPath = args[3] as string | undefined } - // A workspace can have multiple agents, but that's handled - // when opening a workspace unless explicitly specified. - let remoteAuthority = `ssh-remote+${Remote.Prefix}${workspaceOwner}--${workspaceName}` - if (workspaceAgent) { - remoteAuthority += `--${workspaceAgent}` - } - - let newWindow = true - // Open in the existing window if no workspaces are open. - if (!vscode.workspace.workspaceFolders?.length) { - newWindow = false - } - - // If a folder isn't specified, we can try to open a recently opened folder. - if (!folderPath) { - const output: { - workspaces: { folderUri: vscode.Uri; remoteAuthority: string }[] - } = await vscode.commands.executeCommand("_workbench.getRecentlyOpened") - const opened = output.workspaces.filter( - // Filter out `/` since that's added below. - (opened) => opened.folderUri?.authority === remoteAuthority, - ) - if (opened.length > 0) { - let selected: (typeof opened)[0] - - if (opened.length > 1) { - const items: vscode.QuickPickItem[] = opened.map((folder): vscode.QuickPickItem => { - return { - label: folder.folderUri.path, - } - }) - const item = await vscode.window.showQuickPick(items, { - title: "Select a recently opened folder", - }) - if (!item) { - return - } - selected = opened[items.indexOf(item)] - } else { - selected = opened[0] - } - - folderPath = selected.folderUri.path - } - } - - if (folderPath) { - await vscode.commands.executeCommand( - "vscode.openFolder", - vscode.Uri.from({ - scheme: "vscode-remote", - authority: remoteAuthority, - path: folderPath, - }), - // Open this in a new window! - newWindow, - ) - return - } - - // This opens the workspace without an active folder opened. - await vscode.commands.executeCommand("vscode.newWindow", { - remoteAuthority: remoteAuthority, - reuseWindow: !newWindow, - }) + await openWorkspace(workspaceOwner, workspaceName, workspaceAgent, folderPath) } public async updateWorkspace(): Promise { @@ -346,3 +287,76 @@ export class Commands { } } } + +async function openWorkspace( + workspaceOwner: string, + workspaceName: string, + workspaceAgent: string | undefined, + folderPath: string | undefined, +) { + // A workspace can have multiple agents, but that's handled + // when opening a workspace unless explicitly specified. + let remoteAuthority = `ssh-remote+${Remote.Prefix}${workspaceOwner}--${workspaceName}` + if (workspaceAgent) { + remoteAuthority += `--${workspaceAgent}` + } + + let newWindow = true + // Open in the existing window if no workspaces are open. + if (!vscode.workspace.workspaceFolders?.length) { + newWindow = false + } + + // If a folder isn't specified, we can try to open a recently opened folder. + if (!folderPath) { + const output: { + workspaces: { folderUri: vscode.Uri; remoteAuthority: string }[] + } = await vscode.commands.executeCommand("_workbench.getRecentlyOpened") + const opened = output.workspaces.filter( + // Filter out `/` since that's added below. + (opened) => opened.folderUri?.authority === remoteAuthority, + ) + if (opened.length > 0) { + let selected: (typeof opened)[0] + + if (opened.length > 1) { + const items: vscode.QuickPickItem[] = opened.map((folder): vscode.QuickPickItem => { + return { + label: folder.folderUri.path, + } + }) + const item = await vscode.window.showQuickPick(items, { + title: "Select a recently opened folder", + }) + if (!item) { + return + } + selected = opened[items.indexOf(item)] + } else { + selected = opened[0] + } + + folderPath = selected.folderUri.path + } + } + + if (folderPath) { + await vscode.commands.executeCommand( + "vscode.openFolder", + vscode.Uri.from({ + scheme: "vscode-remote", + authority: remoteAuthority, + path: folderPath, + }), + // Open this in a new window! + newWindow, + ) + return + } + + // This opens the workspace without an active folder opened. + await vscode.commands.executeCommand("vscode.newWindow", { + remoteAuthority: remoteAuthority, + reuseWindow: !newWindow, + }) +} diff --git a/src/extension.ts b/src/extension.ts index 7131dd95..b5f02c9a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -87,6 +87,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { vscode.commands.registerCommand("coder.login", commands.login.bind(commands)) vscode.commands.registerCommand("coder.logout", commands.logout.bind(commands)) vscode.commands.registerCommand("coder.open", commands.open.bind(commands)) + vscode.commands.registerCommand("coder.openFromSidebar", commands.openFromSidebar.bind(commands)) vscode.commands.registerCommand("coder.workspace.update", commands.updateWorkspace.bind(commands)) vscode.commands.registerCommand("coder.createWorkspace", commands.createWorkspace.bind(commands)) vscode.commands.registerCommand("coder.navigateToWorkspace", commands.navigateToWorkspace.bind(commands)) diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts index f09b29e4..5cdee575 100644 --- a/src/workspacesProvider.ts +++ b/src/workspacesProvider.ts @@ -1,7 +1,8 @@ import { getWorkspaces } from "coder/site/src/api/api" +import { WorkspaceAgent } from "coder/site/src/api/typesGenerated" import * as path from "path" import * as vscode from "vscode" -import { extractAgentsAndFolderPath } from "./api-helper" +import { extractAgents } from "./api-helper" export enum WorkspaceQuery { Mine = "owner:me", @@ -24,7 +25,19 @@ export class WorkspaceProvider implements vscode.TreeDataProvider { + getChildren(element?: WorkspaceTreeItem): Thenable { + if (element) { + if (element.agents.length > 0) { + return Promise.resolve( + element.agents.map((agent) => { + const label = agent.name + const detail = `Status: ${agent.status}` + return new WorkspaceTreeItem(label, detail, "", "", agent.name, agent.expanded_directory, [], "coderAgent") + }), + ) + } + return Promise.resolve([]) + } return getWorkspaces({ q: this.getWorkspacesQuery }).then((workspaces) => { return workspaces.workspaces.map((workspace) => { const status = @@ -35,22 +48,42 @@ export class WorkspaceProvider implements vscode.TreeDataProvider 1 ? "coderWorkspaceMultipleAgents" : "coderWorkspaceSingleAgent", + ) }) }) } } +type CoderTreeItemType = "coderWorkspaceSingleAgent" | "coderWorkspaceMultipleAgents" | "coderAgent" + export class WorkspaceTreeItem extends vscode.TreeItem { constructor( public readonly label: string, public readonly tooltip: string, public readonly workspaceOwner: string, public readonly workspaceName: string, + public readonly workspaceAgent: string | undefined, public readonly workspaceFolderPath: string | undefined, + public readonly agents: WorkspaceAgent[], + contextValue: CoderTreeItemType, ) { - super(label, vscode.TreeItemCollapsibleState.None) + super( + label, + contextValue === "coderWorkspaceMultipleAgents" + ? vscode.TreeItemCollapsibleState.Collapsed + : vscode.TreeItemCollapsibleState.None, + ) + this.contextValue = contextValue } iconPath = { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy