Skip to content

Commit f6bafef

Browse files
committed
Use new client in commands for the current workspace
These should work now once the clients are pointing to different things.
1 parent 33af7b9 commit f6bafef

File tree

5 files changed

+47
-38
lines changed

5 files changed

+47
-38
lines changed

src/commands.ts

+36-18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ import { Storage } from "./storage"
99
import { OpenableTreeItem } from "./workspacesProvider"
1010

1111
export class Commands {
12+
// These will only be populated when actively connected to a workspace and are
13+
// used in commands. Because commands can be executed by the user, it is not
14+
// possible to pass in arguments, so we have to store the current workspace
15+
// and its client somewhere, separately from the current globally logged-in
16+
// client, since you can connect to workspaces not belonging to whatever you
17+
// are logged into (for convenience; otherwise the recents menu can be a pain
18+
// if you use multiple deployments).
19+
public workspace?: Workspace
20+
public workspaceLogPath?: string
21+
public workspaceRestClient?: Api
22+
1223
public constructor(
1324
private readonly vscodeProposed: typeof vscode,
1425
private readonly restClient: Api,
@@ -162,15 +173,14 @@ export class Commands {
162173
}
163174

164175
/**
165-
* View the logs for the currently logged-in deployment.
176+
* View the logs for the currently connected workspace.
166177
*/
167178
public async viewLogs(): Promise<void> {
168-
// TODO: This will need to be refactored for multi-deployment support.
169-
if (!this.storage.workspaceLogPath) {
170-
vscode.window.showInformationMessage("No logs available.", this.storage.workspaceLogPath || "<unset>")
179+
if (!this.workspaceLogPath) {
180+
vscode.window.showInformationMessage("No logs available.", this.workspaceLogPath || "<unset>")
171181
return
172182
}
173-
const uri = vscode.Uri.file(this.storage.workspaceLogPath)
183+
const uri = vscode.Uri.file(this.workspaceLogPath)
174184
const doc = await vscode.workspace.openTextDocument(uri)
175185
await vscode.window.showTextDocument(doc)
176186
}
@@ -212,14 +222,18 @@ export class Commands {
212222
/**
213223
* Open a link to the workspace in the Coder dashboard.
214224
*
215-
* Must only be called if currently logged in.
225+
* If passing in a workspace, it must belong to the currently logged-in
226+
* deployment.
227+
*
228+
* Otherwise, the currently connected workspace is used (if any).
216229
*/
217230
public async navigateToWorkspace(workspace: OpenableTreeItem) {
218231
if (workspace) {
219232
const uri = this.storage.getUrl() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}`
220233
await vscode.commands.executeCommand("vscode.open", uri)
221-
} else if (this.storage.workspace) {
222-
const uri = this.storage.getUrl() + `/@${this.storage.workspace.owner_name}/${this.storage.workspace.name}`
234+
} else if (this.workspace && this.workspaceRestClient) {
235+
const baseUrl = this.workspaceRestClient.getAxiosInstance().defaults.baseURL
236+
const uri = `${baseUrl}/@${this.workspace.owner_name}/${this.workspace.name}`
223237
await vscode.commands.executeCommand("vscode.open", uri)
224238
} else {
225239
vscode.window.showInformationMessage("No workspace found.")
@@ -229,15 +243,18 @@ export class Commands {
229243
/**
230244
* Open a link to the workspace settings in the Coder dashboard.
231245
*
232-
* Must only be called if currently logged in.
246+
* If passing in a workspace, it must belong to the currently logged-in
247+
* deployment.
248+
*
249+
* Otherwise, the currently connected workspace is used (if any).
233250
*/
234251
public async navigateToWorkspaceSettings(workspace: OpenableTreeItem) {
235252
if (workspace) {
236253
const uri = this.storage.getUrl() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}/settings`
237254
await vscode.commands.executeCommand("vscode.open", uri)
238-
} else if (this.storage.workspace) {
239-
const uri =
240-
this.storage.getUrl() + `/@${this.storage.workspace.owner_name}/${this.storage.workspace.name}/settings`
255+
} else if (this.workspace && this.workspaceRestClient) {
256+
const baseUrl = this.workspaceRestClient.getAxiosInstance().defaults.baseURL
257+
const uri = `${baseUrl}/@${this.workspace.owner_name}/${this.workspace.name}/settings`
241258
await vscode.commands.executeCommand("vscode.open", uri)
242259
} else {
243260
vscode.window.showInformationMessage("No workspace found.")
@@ -248,7 +265,8 @@ export class Commands {
248265
* Open a workspace or agent that is showing in the sidebar.
249266
*
250267
* This essentially just builds the host name and passes it to the VS Code
251-
* Remote SSH extension.
268+
* Remote SSH extension, so it is not necessary to be logged in, although then
269+
* the sidebar would not have any workspaces in it anyway.
252270
*/
253271
public async openFromSidebar(treeItem: OpenableTreeItem) {
254272
if (treeItem) {
@@ -263,9 +281,9 @@ export class Commands {
263281
}
264282

265283
/**
266-
* Open a workspace from the currently logged-in deployment.
284+
* Open a workspace belonging to the currently logged-in deployment.
267285
*
268-
* This must only be called if the REST client is logged in.
286+
* This must only be called if logged into a deployment.
269287
*/
270288
public async open(...args: unknown[]): Promise<void> {
271289
let workspaceOwner: string
@@ -393,20 +411,20 @@ export class Commands {
393411
* this is a no-op.
394412
*/
395413
public async updateWorkspace(): Promise<void> {
396-
if (!this.storage.workspace || !this.storage.restClient) {
414+
if (!this.workspace || !this.workspaceRestClient) {
397415
return
398416
}
399417
const action = await this.vscodeProposed.window.showInformationMessage(
400418
"Update Workspace",
401419
{
402420
useCustom: true,
403421
modal: true,
404-
detail: `${this.storage.workspace.owner_name}/${this.storage.workspace.name} will be updated then this window will reload to watch the build logs and reconnect.`,
422+
detail: `${this.workspace.owner_name}/${this.workspace.name} will be updated then this window will reload to watch the build logs and reconnect.`,
405423
},
406424
"Update",
407425
)
408426
if (action === "Update") {
409-
await this.storage.restClient.updateWorkspaceVersion(this.storage.workspace)
427+
await this.workspaceRestClient.updateWorkspaceVersion(this.workspace)
410428
}
411429
}
412430
}

src/extension.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
150150
if (!vscodeProposed.env.remoteAuthority) {
151151
return
152152
}
153-
const remote = new Remote(vscodeProposed, storage, ctx.extensionMode)
153+
const remote = new Remote(vscodeProposed, storage, commands, ctx.extensionMode)
154154
try {
155155
await remote.setup(vscodeProposed.env.remoteAuthority)
156156
} catch (ex) {

src/remote.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import * as semver from "semver"
1212
import * as vscode from "vscode"
1313
import * as ws from "ws"
1414
import { makeCoderSdk } from "./api"
15+
import { Commands } from "./commands"
1516
import { getHeaderCommand } from "./headers"
1617
import { SSHConfig, SSHValues, defaultSSHConfigResponse, mergeSSHConfigValues } from "./sshConfig"
1718
import { computeSSHProperties, sshSupportsSetEnv } from "./sshSupport"
@@ -27,6 +28,7 @@ export class Remote {
2728
public constructor(
2829
private readonly vscodeProposed: typeof vscode,
2930
private readonly storage: Storage,
31+
private readonly commands: Commands,
3032
private readonly mode: vscode.ExtensionMode,
3133
) {}
3234

@@ -82,7 +84,7 @@ export class Remote {
8284
const token = await this.storage.getSessionToken()
8385
const restClient = await makeCoderSdk(baseUrlRaw, token, this.storage)
8486
// Store for use in commands.
85-
this.storage.restClient = restClient
87+
this.commands.workspaceRestClient = restClient
8688

8789
// First thing is to check the version.
8890
const buildInfo = await restClient.getBuildInfo()
@@ -112,7 +114,7 @@ export class Remote {
112114
let workspace: Workspace
113115
try {
114116
workspace = await restClient.getWorkspaceByOwnerAndName(parts[0], parts[1])
115-
this.storage.workspace = workspace
117+
this.commands.workspace = workspace
116118
} catch (error) {
117119
if (!isAxiosError(error)) {
118120
throw error
@@ -193,7 +195,7 @@ export class Remote {
193195
...workspace,
194196
latest_build: latestBuild,
195197
}
196-
this.storage.workspace = workspace
198+
this.commands.workspace = workspace
197199
}
198200

199201
// If a build is running we should stream the logs to the user so they can
@@ -251,7 +253,7 @@ export class Remote {
251253
})
252254
writeEmitter.fire("Build complete")
253255
workspace = await restClient.getWorkspace(workspace.id)
254-
this.storage.workspace = workspace
256+
this.commands.workspace = workspace
255257
terminal.dispose()
256258

257259
if (buildComplete) {
@@ -420,7 +422,7 @@ export class Remote {
420422
return
421423
}
422424
refreshWorkspaceUpdatedStatus(workspace)
423-
this.storage.workspace = workspace
425+
this.commands.workspace = workspace
424426
workspaceUpdate.fire(workspace)
425427
if (workspace.latest_build.status === "stopping" || workspace.latest_build.status === "stopped") {
426428
const action = this.vscodeProposed.window.showInformationMessage(
@@ -520,7 +522,7 @@ export class Remote {
520522
return
521523
}
522524
disposables.push(this.showNetworkUpdates(pid))
523-
this.storage.workspaceLogPath = path.join(this.storage.getLogPath(), `${pid}.log`)
525+
this.commands.workspaceLogPath = path.join(this.storage.getLogPath(), `${pid}.log`)
524526
})
525527

526528
// Register the label formatter again because SSH overrides it!

src/storage.ts

-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Api } from "coder/site/src/api/api"
2-
import { Workspace } from "coder/site/src/api/typesGenerated"
32
import { createWriteStream } from "fs"
43
import fs from "fs/promises"
54
import { ensureDir } from "fs-extra"
@@ -15,18 +14,6 @@ import { getHeaderCommand, getHeaders } from "./headers"
1514
const MAX_URLS = 10
1615

1716
export class Storage {
18-
// These will only be populated when actively connected to a workspace and are
19-
// used in commands. Because commands can be executed by the user, it is not
20-
// possible to pass in arguments, so we have to store the current workspace
21-
// and client somewhere, separately from the current login, since you can
22-
// connect to workspaces not belonging to whatever you are logged into (for
23-
// convenience; otherwise the recents menu can be a pain if you use multiple
24-
// deployments).
25-
// TODO: Should maybe store on the Commands class instead.
26-
public workspace?: Workspace
27-
public workspaceLogPath?: string
28-
public restClient?: Api
29-
3017
constructor(
3118
private readonly output: vscode.OutputChannel,
3219
private readonly memento: vscode.Memento,

src/workspacesProvider.ts

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type AgentWatcher = {
2626
/**
2727
* Polls workspaces using the provided REST client and renders them in a tree.
2828
*
29+
* Polling does not start until fetchAndRefresh() is called at least once.
30+
*
2931
* If the poll fails or the client has no URL configured, clear the tree and
3032
* abort polling until fetchAndRefresh() is called again.
3133
*/

0 commit comments

Comments
 (0)