From 66bd03a58f128d7393ab66bd6496b22bf535688d Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 21 Mar 2023 17:34:47 -0300 Subject: [PATCH 01/10] WIP: adding tree view to support crud workspaces --- package.json | 29 ++++++++++++++++++++++------- src/extension.ts | 3 +++ src/workspacesProvider.ts | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 src/workspacesProvider.ts diff --git a/package.json b/package.json index 1553bdff..35226be2 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "coder": [ { "id": "coderRemote", - "name": "", + "name": "Workspaces", "visibility": "visible", "icon": "media/logo.svg", "contextualTitle": "Coder Remote" @@ -54,11 +54,6 @@ "view": "coderRemote", "contents": "Coder is a platform that provisions remote development environments. \n[Login](command:coder.login)", "when": "!coder.authenticated && coder.loaded" - }, - { - "view": "coderRemote", - "contents": "You're logged in! \n[Open Workspace](command:coder.open)", - "when": "coder.authenticated && coder.loaded" } ], "commands": [ @@ -79,7 +74,27 @@ "title": "Coder: Update Workspace", "when": "coder.workspace.updatable" } - ] + ], + "menus": { + "view/title": [ + { + "command": "coder.logout", + "when": "coder.authenticated" + }, + { + "command": "coder.createWorkspace", + "when": "coder.authenticated", + "group": "navigation" + } + ], + "view/item/context": [ + { + "command": "coder.open", + "when": "coder.authenticated", + "group": "inline" + } + ] + } }, "scripts": { "vscode:prepublish": "yarn package", diff --git a/src/extension.ts b/src/extension.ts index e5e73cd7..b7ef102e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,12 +6,15 @@ import * as vscode from "vscode" import { Commands } from "./commands" import { Remote } from "./remote" import { Storage } from "./storage" +import { WorkspaceProvider } from "./workspacesProvider" export async function activate(ctx: vscode.ExtensionContext): Promise { const output = vscode.window.createOutputChannel("Coder") const storage = new Storage(output, ctx.globalState, ctx.secrets, ctx.globalStorageUri, ctx.logUri) await storage.init() + vscode.window.registerTreeDataProvider("coderRemote", new WorkspaceProvider()) + getAuthenticatedUser() .then(() => { vscode.commands.executeCommand("setContext", "coder.authenticated", true) diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts new file mode 100644 index 00000000..855d1ce2 --- /dev/null +++ b/src/workspacesProvider.ts @@ -0,0 +1,32 @@ +import { getWorkspaces } from "coder/site/src/api/api" +import * as path from "path" +import * as vscode from "vscode" + +export class WorkspaceProvider implements vscode.TreeDataProvider { + getTreeItem(element: Dependency): vscode.TreeItem { + return element + } + + getChildren(): Thenable { + return getWorkspaces({ + q: "owner:me", + }).then((workspaces) => { + const exampleWorkspaces = [{ name: "example1" }, { name: "example2" }] + return [...workspaces.workspaces, ...exampleWorkspaces].map( + (workspace) => new Dependency(workspace.name, vscode.TreeItemCollapsibleState.None), + ) + }) + } +} + +class Dependency extends vscode.TreeItem { + constructor(public readonly label: string, public readonly collapsibleState: vscode.TreeItemCollapsibleState) { + super(label, collapsibleState) + this.tooltip = `${this.label}` + } + + iconPath = { + light: path.join(__filename, "..", "..", "media", "logo.svg"), + dark: path.join(__filename, "..", "..", "media", "logo.svg"), + } +} From 4612bea6af37e4cb3b7b3efe4f8a2aecc439bdfb Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Fri, 24 Mar 2023 11:54:50 -0300 Subject: [PATCH 02/10] ::coffee:: wip --- .gitignore | 3 ++- package.json | 21 +++++++++++++++----- src/commands.ts | 5 +++++ src/extension.ts | 1 + src/workspacesProvider.ts | 42 ++++++++++++++++++++++++++++----------- 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index d535c22b..75f80c5f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ /.vscode-test/ /.nyc_output/ /coverage/ -*.vsix \ No newline at end of file +*.vsix +yarn-error.log diff --git a/package.json b/package.json index 35226be2..ecdddfed 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,7 @@ "id": "coderRemote", "name": "Workspaces", "visibility": "visible", - "icon": "media/logo.svg", - "contextualTitle": "Coder Remote" + "icon": "media/logo.svg" } ] }, @@ -69,6 +68,14 @@ "command": "coder.open", "title": "Coder: Open Workspace" }, + { + "command": "coder.createWorkspace", + "title": "Create Workspace" + }, + { + "command": "coder.removeWorkspace", + "title": "Remove Workspace" + }, { "command": "coder.workspace.update", "title": "Coder: Update Workspace", @@ -79,19 +86,23 @@ "view/title": [ { "command": "coder.logout", - "when": "coder.authenticated" + "when": "coder.authenticated && view == coderRemote" }, { "command": "coder.createWorkspace", - "when": "coder.authenticated", + "when": "coder.authenticated && view == coderRemote", "group": "navigation" } ], "view/item/context": [ { "command": "coder.open", - "when": "coder.authenticated", + "when": "coder.authenticated && viewItem.label !== 'My Workspaces' && view == coderRemote", "group": "inline" + }, + { + "command": "coder.removeWorkspace", + "when": "coder.authenticated" } ] } diff --git a/src/commands.ts b/src/commands.ts index ccc2c653..f8bfde1f 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -108,6 +108,11 @@ export class Commands { }) } + public async createWorkspace(): Promise { + const uri = this.storage.getURL() + "/templates" + await vscode.commands.executeCommand("vscode.open", uri) + } + public async open(...args: string[]): Promise { let workspaceOwner: string let workspaceName: string diff --git a/src/extension.ts b/src/extension.ts index b7ef102e..56b9e906 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -79,6 +79,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { vscode.commands.registerCommand("coder.logout", commands.logout.bind(commands)) vscode.commands.registerCommand("coder.open", commands.open.bind(commands)) vscode.commands.registerCommand("coder.workspace.update", commands.updateWorkspace.bind(commands)) + vscode.commands.registerCommand("coder.createWorkspace", commands.createWorkspace.bind(commands)) // Since the "onResolveRemoteAuthority:ssh-remote" activation event exists // in package.json we're able to perform actions before the authority is diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts index 855d1ce2..43d6fc76 100644 --- a/src/workspacesProvider.ts +++ b/src/workspacesProvider.ts @@ -2,24 +2,42 @@ import { getWorkspaces } from "coder/site/src/api/api" import * as path from "path" import * as vscode from "vscode" -export class WorkspaceProvider implements vscode.TreeDataProvider { - getTreeItem(element: Dependency): vscode.TreeItem { +export class WorkspaceProvider implements vscode.TreeDataProvider { + getTreeItem(element: TreeItem): vscode.TreeItem { return element } - getChildren(): Thenable { - return getWorkspaces({ - q: "owner:me", - }).then((workspaces) => { - const exampleWorkspaces = [{ name: "example1" }, { name: "example2" }] - return [...workspaces.workspaces, ...exampleWorkspaces].map( - (workspace) => new Dependency(workspace.name, vscode.TreeItemCollapsibleState.None), - ) - }) + getChildren(element?: TreeItem): Thenable { + if (!element) { + return Promise.resolve([ + new TreeItem("My Workspaces", vscode.TreeItemCollapsibleState.Expanded), + new TreeItem("All Workspaces", vscode.TreeItemCollapsibleState.None), + ]) + } + if (element.label === "My Workspaces") { + return getWorkspaces({ + q: "owner:me", + }).then((workspaces) => { + return workspaces.workspaces.map( + (workspace) => new TreeItem(workspace.name, vscode.TreeItemCollapsibleState.None), + ) + }) + } + if (element.label === "All Workspaces") { + return getWorkspaces({ + q: "owner:all", + }).then((workspaces) => { + const exampleWorkspaces = [{ name: "example1" }, { name: "example2" }] + return [...workspaces.workspaces, ...exampleWorkspaces].map( + (workspace) => new TreeItem(workspace.name, vscode.TreeItemCollapsibleState.None), + ) + }) + } + return Promise.resolve([]) } } -class Dependency extends vscode.TreeItem { +class TreeItem extends vscode.TreeItem { constructor(public readonly label: string, public readonly collapsibleState: vscode.TreeItemCollapsibleState) { super(label, collapsibleState) this.tooltip = `${this.label}` From 255d6b6b76b9e4b03b4db3bcf16a15df5ebeede8 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 28 Mar 2023 11:17:09 -0300 Subject: [PATCH 03/10] simplify worktreeprovider --- package.json | 22 ++++++++++++---------- src/extension.ts | 3 ++- src/workspacesProvider.ts | 34 +++++++--------------------------- 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/package.json b/package.json index ecdddfed..7949bbc6 100644 --- a/package.json +++ b/package.json @@ -41,8 +41,14 @@ "views": { "coder": [ { - "id": "coderRemote", - "name": "Workspaces", + "id": "myWorkspaces", + "name": "My Workspaces", + "visibility": "visible", + "icon": "media/logo.svg" + }, + { + "id": "allWorkspaces", + "name": "All Workspaces", "visibility": "visible", "icon": "media/logo.svg" } @@ -50,7 +56,7 @@ }, "viewsWelcome": [ { - "view": "coderRemote", + "view": "myWorkspaces", "contents": "Coder is a platform that provisions remote development environments. \n[Login](command:coder.login)", "when": "!coder.authenticated && coder.loaded" } @@ -86,23 +92,19 @@ "view/title": [ { "command": "coder.logout", - "when": "coder.authenticated && view == coderRemote" + "when": "coder.authenticated && view == myWorkspaces" }, { "command": "coder.createWorkspace", - "when": "coder.authenticated && view == coderRemote", + "when": "coder.authenticated && view == myWorkspaces", "group": "navigation" } ], "view/item/context": [ { "command": "coder.open", - "when": "coder.authenticated && viewItem.label !== 'My Workspaces' && view == coderRemote", + "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces", "group": "inline" - }, - { - "command": "coder.removeWorkspace", - "when": "coder.authenticated" } ] } diff --git a/src/extension.ts b/src/extension.ts index 56b9e906..1d1a6caf 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,7 +13,8 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { const storage = new Storage(output, ctx.globalState, ctx.secrets, ctx.globalStorageUri, ctx.logUri) await storage.init() - vscode.window.registerTreeDataProvider("coderRemote", new WorkspaceProvider()) + vscode.window.registerTreeDataProvider("myWorkspaces", new WorkspaceProvider("owner:me")) + vscode.window.registerTreeDataProvider("allWorkspaces", new WorkspaceProvider()) getAuthenticatedUser() .then(() => { diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts index 43d6fc76..61b4e478 100644 --- a/src/workspacesProvider.ts +++ b/src/workspacesProvider.ts @@ -3,37 +3,17 @@ import * as path from "path" import * as vscode from "vscode" export class WorkspaceProvider implements vscode.TreeDataProvider { + constructor(private readonly getWorkspacesQuery?: string) {} getTreeItem(element: TreeItem): vscode.TreeItem { return element } - getChildren(element?: TreeItem): Thenable { - if (!element) { - return Promise.resolve([ - new TreeItem("My Workspaces", vscode.TreeItemCollapsibleState.Expanded), - new TreeItem("All Workspaces", vscode.TreeItemCollapsibleState.None), - ]) - } - if (element.label === "My Workspaces") { - return getWorkspaces({ - q: "owner:me", - }).then((workspaces) => { - return workspaces.workspaces.map( - (workspace) => new TreeItem(workspace.name, vscode.TreeItemCollapsibleState.None), - ) - }) - } - if (element.label === "All Workspaces") { - return getWorkspaces({ - q: "owner:all", - }).then((workspaces) => { - const exampleWorkspaces = [{ name: "example1" }, { name: "example2" }] - return [...workspaces.workspaces, ...exampleWorkspaces].map( - (workspace) => new TreeItem(workspace.name, vscode.TreeItemCollapsibleState.None), - ) - }) - } - return Promise.resolve([]) + getChildren(): Thenable { + return getWorkspaces({ q: this.getWorkspacesQuery }).then((workspaces) => { + return workspaces.workspaces.map( + (workspace) => new TreeItem(workspace.name, vscode.TreeItemCollapsibleState.None), + ) + }) } } From e9813d8bb1c2c7252aebbb7030f6de89ccc50796 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 28 Mar 2023 15:17:23 -0300 Subject: [PATCH 04/10] implemente open workspace command --- package.json | 8 ++++++-- src/api-helper.ts | 16 +++++++++++++++ src/commands.ts | 31 +++++++++++++++++----------- src/extension.ts | 7 ++++--- src/workspacesProvider.ts | 43 +++++++++++++++++++++++++++++---------- 5 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 src/api-helper.ts diff --git a/package.json b/package.json index 7949bbc6..5f672a8e 100644 --- a/package.json +++ b/package.json @@ -79,8 +79,8 @@ "title": "Create Workspace" }, { - "command": "coder.removeWorkspace", - "title": "Remove Workspace" + "command": "coder.navigateToWorkspace", + "title": "Open Workspace in Browser" }, { "command": "coder.workspace.update", @@ -105,6 +105,10 @@ "command": "coder.open", "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces", "group": "inline" + }, + { + "command": "coder.navigateToWorkspace", + "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces" } ] } diff --git a/src/api-helper.ts b/src/api-helper.ts new file mode 100644 index 00000000..75c0af83 --- /dev/null +++ b/src/api-helper.ts @@ -0,0 +1,16 @@ +import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated" + +export function extractAgentsAndFolderPath( + workspace: Workspace, +): [agents: WorkspaceAgent[], folderPath: string | undefined] { + // TODO: multiple agent support + 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] +} diff --git a/src/commands.ts b/src/commands.ts index f8bfde1f..4250fb2c 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -2,8 +2,10 @@ import axios from "axios" import { getAuthenticatedUser, getWorkspaces, updateWorkspaceVersion } from "coder/site/src/api/api" import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated" import * as vscode from "vscode" +import { extractAgentsAndFolderPath } from "./api-helper" import { Remote } from "./remote" import { Storage } from "./storage" +import { WorkspaceTreeItem } from "./workspacesProvider" export class Commands { public constructor(private readonly vscodeProposed: typeof vscode, private readonly storage: Storage) {} @@ -113,7 +115,12 @@ export class Commands { await vscode.commands.executeCommand("vscode.open", uri) } - public async open(...args: string[]): Promise { + public async navigateToWorkspace(workspace: WorkspaceTreeItem): Promise { + const uri = this.storage.getURL() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}` + await vscode.commands.executeCommand("vscode.open", uri) + } + + public async open(...args: unknown[]): Promise { let workspaceOwner: string let workspaceName: string let folderPath: string | undefined @@ -170,19 +177,19 @@ 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 - } + const [, folderPathExtracted] = extractAgentsAndFolderPath(workspace) + folderPath = folderPathExtracted + } 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] - workspaceName = args[1] + workspaceOwner = args[0] as string + workspaceName = args[1] as string // workspaceAgent is reserved for args[2], but multiple agents aren't supported yet. - folderPath = args[3] + folderPath = args[3] as string | undefined } // A workspace can have multiple agents, but that's handled diff --git a/src/extension.ts b/src/extension.ts index 1d1a6caf..082033b5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,15 +6,15 @@ import * as vscode from "vscode" import { Commands } from "./commands" import { Remote } from "./remote" import { Storage } from "./storage" -import { WorkspaceProvider } from "./workspacesProvider" +import { WorkspaceQuery, WorkspaceProvider } from "./workspacesProvider" export async function activate(ctx: vscode.ExtensionContext): Promise { const output = vscode.window.createOutputChannel("Coder") const storage = new Storage(output, ctx.globalState, ctx.secrets, ctx.globalStorageUri, ctx.logUri) await storage.init() - vscode.window.registerTreeDataProvider("myWorkspaces", new WorkspaceProvider("owner:me")) - vscode.window.registerTreeDataProvider("allWorkspaces", new WorkspaceProvider()) + vscode.window.registerTreeDataProvider("myWorkspaces", new WorkspaceProvider(WorkspaceQuery.Mine)) + vscode.window.registerTreeDataProvider("allWorkspaces", new WorkspaceProvider(WorkspaceQuery.All)) getAuthenticatedUser() .then(() => { @@ -81,6 +81,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { vscode.commands.registerCommand("coder.open", commands.open.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)) // Since the "onResolveRemoteAuthority:ssh-remote" activation event exists // in package.json we're able to perform actions before the authority is diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts index 61b4e478..a34d6803 100644 --- a/src/workspacesProvider.ts +++ b/src/workspacesProvider.ts @@ -1,26 +1,47 @@ import { getWorkspaces } from "coder/site/src/api/api" import * as path from "path" import * as vscode from "vscode" +import { extractAgentsAndFolderPath } from "./api-helper" -export class WorkspaceProvider implements vscode.TreeDataProvider { - constructor(private readonly getWorkspacesQuery?: string) {} - getTreeItem(element: TreeItem): vscode.TreeItem { +export enum WorkspaceQuery { + Mine = "owner:me", + All = "", +} + +export class WorkspaceProvider implements vscode.TreeDataProvider { + constructor(private readonly getWorkspacesQuery: WorkspaceQuery) {} + + getTreeItem(element: WorkspaceTreeItem): vscode.TreeItem { return element } - getChildren(): Thenable { + getChildren(): Thenable { return getWorkspaces({ q: this.getWorkspacesQuery }).then((workspaces) => { - return workspaces.workspaces.map( - (workspace) => new TreeItem(workspace.name, vscode.TreeItemCollapsibleState.None), - ) + return workspaces.workspaces.map((workspace) => { + const status = + workspace.latest_build.status.substring(0, 1).toUpperCase() + workspace.latest_build.status.substring(1) + + const label = + this.getWorkspacesQuery === WorkspaceQuery.All + ? `${workspace.owner_name} / ${workspace.name}` + : workspace.name + const detail = `Template: ${workspace.template_display_name || workspace.template_name} • Status: ${status}` + const [, folderPath] = extractAgentsAndFolderPath(workspace) + return new WorkspaceTreeItem(label, detail, workspace.owner_name, workspace.name, folderPath) + }) }) } } -class TreeItem extends vscode.TreeItem { - constructor(public readonly label: string, public readonly collapsibleState: vscode.TreeItemCollapsibleState) { - super(label, collapsibleState) - this.tooltip = `${this.label}` +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 workspaceFolderPath: string | undefined, + ) { + super(label, vscode.TreeItemCollapsibleState.None) } iconPath = { From 40241893419679999b3fcc9b57d9ce6f80d36750 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 28 Mar 2023 15:32:14 -0300 Subject: [PATCH 05/10] lint --- src/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands.ts b/src/commands.ts index 4250fb2c..8d973887 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -1,6 +1,6 @@ import axios from "axios" import { getAuthenticatedUser, getWorkspaces, updateWorkspaceVersion } from "coder/site/src/api/api" -import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated" +import { Workspace } from "coder/site/src/api/typesGenerated" import * as vscode from "vscode" import { extractAgentsAndFolderPath } from "./api-helper" import { Remote } from "./remote" From d31ba11ef9febd0a4e9b6fcb04f0bd3f76a26458 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 28 Mar 2023 16:06:24 -0300 Subject: [PATCH 06/10] copy changes --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5f672a8e..23368733 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ }, { "command": "coder.navigateToWorkspace", - "title": "Open Workspace in Browser" + "title": "Navigate to Workspace Page" }, { "command": "coder.workspace.update", From 2be39ce241f3ec36f56e0c40a3b7d50b65e8a2a0 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 28 Mar 2023 16:58:07 -0300 Subject: [PATCH 07/10] login menu option --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 23368733..f95a5003 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,10 @@ "command": "coder.logout", "when": "coder.authenticated && view == myWorkspaces" }, + { + "command": "coder.login", + "when": "!coder.authenticated && view == myWorkspaces" + }, { "command": "coder.createWorkspace", "when": "coder.authenticated && view == myWorkspaces", From ddfe7f84b91a326f35cc46787fdd85e9ea0098ce Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 28 Mar 2023 17:08:00 -0300 Subject: [PATCH 08/10] add icons --- package.json | 29 ++++++++++++++++++++++++----- src/extension.ts | 11 +++++++++-- src/workspacesProvider.ts | 9 +++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index f95a5003..9fb3e276 100644 --- a/package.json +++ b/package.json @@ -68,24 +68,37 @@ }, { "command": "coder.logout", - "title": "Coder: Logout" + "title": "Coder: Logout", + "when": "coder.authenticated", + "icon": "$(sign-out)" }, { "command": "coder.open", - "title": "Coder: Open Workspace" + "title": "Coder: Open Workspace", + "icon": "$(play)" }, { "command": "coder.createWorkspace", - "title": "Create Workspace" + "title": "Create Workspace", + "when": "coder.authenticated", + "icon": "$(add)" }, { "command": "coder.navigateToWorkspace", - "title": "Navigate to Workspace Page" + "title": "Navigate to Workspace Page", + "when": "coder.authenticated", + "icon": "$(link-external)" }, { "command": "coder.workspace.update", "title": "Coder: Update Workspace", "when": "coder.workspace.updatable" + }, + { + "command": "coder.refreshWorkspaces", + "title": "Coder: Refresh Workspace", + "icon": "$(refresh)", + "when": "coder.authenticated" } ], "menus": { @@ -102,6 +115,11 @@ "command": "coder.createWorkspace", "when": "coder.authenticated && view == myWorkspaces", "group": "navigation" + }, + { + "command": "coder.refreshWorkspaces", + "when": "coder.authenticated && view == myWorkspaces", + "group": "navigation" } ], "view/item/context": [ @@ -112,7 +130,8 @@ }, { "command": "coder.navigateToWorkspace", - "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces" + "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces", + "group": "inline" } ] } diff --git a/src/extension.ts b/src/extension.ts index 082033b5..ca894d09 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,8 +13,11 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { const storage = new Storage(output, ctx.globalState, ctx.secrets, ctx.globalStorageUri, ctx.logUri) await storage.init() - vscode.window.registerTreeDataProvider("myWorkspaces", new WorkspaceProvider(WorkspaceQuery.Mine)) - vscode.window.registerTreeDataProvider("allWorkspaces", new WorkspaceProvider(WorkspaceQuery.All)) + const myWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.Mine) + const allWorkspacesProvider = new WorkspaceProvider(WorkspaceQuery.All) + + vscode.window.registerTreeDataProvider("myWorkspaces", myWorkspacesProvider) + vscode.window.registerTreeDataProvider("allWorkspaces", allWorkspacesProvider) getAuthenticatedUser() .then(() => { @@ -82,6 +85,10 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { 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)) + vscode.commands.registerCommand("coder.refreshWorkspaces", () => { + myWorkspacesProvider.refresh() + allWorkspacesProvider.refresh() + }) // Since the "onResolveRemoteAuthority:ssh-remote" activation event exists // in package.json we're able to perform actions before the authority is diff --git a/src/workspacesProvider.ts b/src/workspacesProvider.ts index a34d6803..f09b29e4 100644 --- a/src/workspacesProvider.ts +++ b/src/workspacesProvider.ts @@ -11,6 +11,15 @@ export enum WorkspaceQuery { export class WorkspaceProvider implements vscode.TreeDataProvider { constructor(private readonly getWorkspacesQuery: WorkspaceQuery) {} + private _onDidChangeTreeData: vscode.EventEmitter = + new vscode.EventEmitter() + readonly onDidChangeTreeData: vscode.Event = + this._onDidChangeTreeData.event + + refresh(): void { + this._onDidChangeTreeData.fire() + } + getTreeItem(element: WorkspaceTreeItem): vscode.TreeItem { return element } From 035af4aa47803cff429927e7b4ef49bb41c5f2c4 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 28 Mar 2023 17:31:28 -0300 Subject: [PATCH 09/10] add workspace settings button --- package.json | 11 +++++++++++ src/commands.ts | 26 +++++++++++++++++++++++--- src/extension.ts | 4 ++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9fb3e276..2b3f0132 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,12 @@ "when": "coder.authenticated", "icon": "$(link-external)" }, + { + "command": "coder.navigateToWorkspaceSettings", + "title": "Edit Workspace Settings", + "when": "coder.authenticated", + "icon": "$(settings-gear)" + }, { "command": "coder.workspace.update", "title": "Coder: Update Workspace", @@ -132,6 +138,11 @@ "command": "coder.navigateToWorkspace", "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces", "group": "inline" + }, + { + "command": "coder.navigateToWorkspaceSettings", + "when": "coder.authenticated && view == myWorkspaces || coder.authenticated && view == allWorkspaces", + "group": "inline" } ] } diff --git a/src/commands.ts b/src/commands.ts index 8d973887..573529ef 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -115,9 +115,29 @@ export class Commands { await vscode.commands.executeCommand("vscode.open", uri) } - public async navigateToWorkspace(workspace: WorkspaceTreeItem): Promise { - const uri = this.storage.getURL() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}` - await vscode.commands.executeCommand("vscode.open", uri) + public async navigateToWorkspace(workspace: WorkspaceTreeItem) { + if (workspace) { + const uri = this.storage.getURL() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}` + await vscode.commands.executeCommand("vscode.open", uri) + } else if (this.storage.workspace) { + const uri = this.storage.getURL() + `/@${this.storage.workspace.owner_name}/${this.storage.workspace.name}` + await vscode.commands.executeCommand("vscode.open", uri) + } else { + vscode.window.showInformationMessage("No workspace found.") + } + } + + public async navigateToWorkspaceSettings(workspace: WorkspaceTreeItem) { + if (workspace) { + const uri = this.storage.getURL() + `/@${workspace.workspaceOwner}/${workspace.workspaceName}/settings` + await vscode.commands.executeCommand("vscode.open", uri) + } else if (this.storage.workspace) { + const uri = + this.storage.getURL() + `/@${this.storage.workspace.owner_name}/${this.storage.workspace.name}/settings` + await vscode.commands.executeCommand("vscode.open", uri) + } else { + vscode.window.showInformationMessage("No workspace found.") + } } public async open(...args: unknown[]): Promise { diff --git a/src/extension.ts b/src/extension.ts index ca894d09..fa7bb585 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -85,6 +85,10 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { 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)) + vscode.commands.registerCommand( + "coder.navigateToWorkspaceSettings", + commands.navigateToWorkspaceSettings.bind(commands), + ) vscode.commands.registerCommand("coder.refreshWorkspaces", () => { myWorkspacesProvider.refresh() allWorkspacesProvider.refresh() From b0115028e0050484eff635c68cb8247aaa87d1f0 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Wed, 29 Mar 2023 10:02:15 -0300 Subject: [PATCH 10/10] only show all workspaces tab for coder owners --- package.json | 3 ++- src/commands.ts | 3 +++ src/extension.ts | 9 +++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 2b3f0132..0c114daf 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "id": "allWorkspaces", "name": "All Workspaces", "visibility": "visible", - "icon": "media/logo.svg" + "icon": "media/logo.svg", + "when": "coder.authenticated && coder.isOwner" } ] }, diff --git a/src/commands.ts b/src/commands.ts index 573529ef..bd4fc1b5 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -81,6 +81,9 @@ export class Commands { throw new Error("Failed to get authenticated user") } await vscode.commands.executeCommand("setContext", "coder.authenticated", true) + if (user.roles.find((role) => role.name === "owner")) { + await vscode.commands.executeCommand("setContext", "coder.isOwner", true) + } vscode.window .showInformationMessage( `Welcome to Coder, ${user.username}!`, diff --git a/src/extension.ts b/src/extension.ts index fa7bb585..7131dd95 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -20,8 +20,13 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { vscode.window.registerTreeDataProvider("allWorkspaces", allWorkspacesProvider) getAuthenticatedUser() - .then(() => { - vscode.commands.executeCommand("setContext", "coder.authenticated", true) + .then(async (user) => { + if (user) { + vscode.commands.executeCommand("setContext", "coder.authenticated", true) + if (user.roles.find((role) => role.name === "owner")) { + await vscode.commands.executeCommand("setContext", "coder.isOwner", true) + } + } }) .catch(() => { // Not authenticated! 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