Skip to content

Commit e8de998

Browse files
committed
feat: add workspace_apps configuration to control apps shown in workspace table
- Added workspace_apps field to terraform coder_agent resource - Updated proto definition to include workspace_apps - Modified frontend WorkspaceApps component to respect configured apps - Allows specifying which apps (built-in and custom) appear in the workspace table - Maximum of 4 apps displayed, in the order specified
1 parent 550c22d commit e8de998

File tree

5 files changed

+121
-8
lines changed

5 files changed

+121
-8
lines changed

codersdk/workspaceagents.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ type WorkspaceAgent struct {
169169
Subsystems []AgentSubsystem `json:"subsystems"`
170170
Health WorkspaceAgentHealth `json:"health"` // Health reports the health of the agent.
171171
DisplayApps []DisplayApp `json:"display_apps"`
172+
WorkspaceApps []string `json:"workspace_apps"`
172173
LogSources []WorkspaceAgentLogSource `json:"log_sources"`
173174
Scripts []WorkspaceAgentScript `json:"scripts"`
174175

provisioner/terraform/resources.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type agentAttributes struct {
5959
MOTDFile string `mapstructure:"motd_file"`
6060
Metadata []agentMetadata `mapstructure:"metadata"`
6161
DisplayApps []agentDisplayAppsAttributes `mapstructure:"display_apps"`
62+
WorkspaceApps []string `mapstructure:"workspace_apps"`
6263
Order int64 `mapstructure:"order"`
6364
ResourcesMonitoring []agentResourcesMonitoring `mapstructure:"resources_monitoring"`
6465
}
@@ -348,6 +349,7 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
348349
ResourcesMonitoring: resourcesMonitoring,
349350
Metadata: metadata,
350351
DisplayApps: displayApps,
352+
WorkspaceApps: attrs.WorkspaceApps,
351353
Order: attrs.Order,
352354
ApiKeyScope: attrs.APIKeyScope,
353355
}

provisionersdk/proto/provisioner.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ message Agent {
188188
ResourcesMonitoring resources_monitoring = 24;
189189
repeated Devcontainer devcontainers = 25;
190190
string api_key_scope = 26;
191+
repeated string workspace_apps = 27;
191192
}
192193

193194
enum AppSharingLevel {

site/src/pages/WorkspacesPage/WorkspacesTable.tsx

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -718,16 +718,88 @@ const WorkspaceApps: FC<WorkspaceAppsProps> = ({ workspace }) => {
718718
return null;
719719
}
720720

721-
const builtinApps = new Set(agent.display_apps);
722-
builtinApps.delete("port_forwarding_helper");
723-
builtinApps.delete("ssh_helper");
721+
// If workspace_apps is configured, use that list instead of display_apps
722+
const configuredApps = (agent as any).workspace_apps as string[] | undefined;
723+
const buttons: ReactNode[] = [];
724724

725-
const remainingSlots = WORKSPACE_APPS_SLOTS - builtinApps.size;
726-
const userApps = agent.apps
727-
.filter((app) => app.health === "healthy" && !app.hidden)
728-
.slice(0, remainingSlots);
725+
if (configuredApps && configuredApps.length > 0) {
726+
// Use the configured apps list
727+
for (const appId of configuredApps.slice(0, WORKSPACE_APPS_SLOTS)) {
728+
if (appId === "vscode") {
729+
buttons.push(
730+
<BaseIconLink
731+
key="vscode"
732+
isLoading={!token}
733+
label="Open VS Code in Browser"
734+
href={getVSCodeHref("vscode", {
735+
owner: workspace.owner_name,
736+
workspace: workspace.name,
737+
agent: agent.name,
738+
token: token ?? "",
739+
folder: agent.expanded_directory,
740+
})}
741+
>
742+
<VSCodeIcon />
743+
</BaseIconLink>,
744+
);
745+
} else if (appId === "vscode_insiders") {
746+
buttons.push(
747+
<BaseIconLink
748+
key="vscode-insiders"
749+
label="Open VS Code Insiders in Browser"
750+
isLoading={!token}
751+
href={getVSCodeHref("vscode-insiders", {
752+
owner: workspace.owner_name,
753+
workspace: workspace.name,
754+
agent: agent.name,
755+
token: token ?? "",
756+
folder: agent.expanded_directory,
757+
})}
758+
>
759+
<VSCodeInsidersIcon />
760+
</BaseIconLink>,
761+
);
762+
} else if (appId === "web_terminal") {
763+
buttons.push(
764+
<BaseIconLink
765+
key="terminal"
766+
isLoading={!token}
767+
label="Open Terminal"
768+
href={getTerminalHref({
769+
owner: workspace.owner_name,
770+
workspace: workspace.name,
771+
agent: agent.name,
772+
token: token ?? "",
773+
})}
774+
>
775+
<SquareTerminalIcon />
776+
</BaseIconLink>,
777+
);
778+
} else {
779+
// Check if it's a user app
780+
const app = agent.apps.find((a) => a.slug === appId || a.id === appId);
781+
if (app && app.health === "healthy" && !app.hidden) {
782+
buttons.push(
783+
<IconAppLink
784+
key={app.id}
785+
app={app}
786+
workspace={workspace}
787+
agent={agent}
788+
/>,
789+
);
790+
}
791+
}
792+
}
793+
} else {
794+
// Fall back to the original behavior
795+
const builtinApps = new Set(agent.display_apps);
796+
builtinApps.delete("port_forwarding_helper");
797+
builtinApps.delete("ssh_helper");
729798

730-
const buttons: ReactNode[] = [];
799+
const remainingSlots = WORKSPACE_APPS_SLOTS - builtinApps.size;
800+
const userApps = agent.apps
801+
.filter((app) => app.health === "healthy" && !app.hidden)
802+
.slice(0, remainingSlots);
731803

732804
if (builtinApps.has("vscode")) {
733805
buttons.push(
@@ -798,6 +870,7 @@ const WorkspaceApps: FC<WorkspaceAppsProps> = ({ workspace }) => {
798870
</BaseIconLink>,
799871
);
800872
}
873+
} // Close the else block for fallback behavior
801874

802875
buttons.push();
803876

vscode-button-text.patch

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
From 550c22de57f4dbe68bf97482db5c675de2b2f19a Mon Sep 17 00:00:00 2001
2+
From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com>
3+
Date: Sat, 19 Jul 2025 19:01:00 +0000
4+
Subject: [PATCH] feat: update workspace button text to show 'Open VS Code in
5+
Browser'
6+
7+
Updated the button labels on the /workspaces page to clearly indicate that VS Code opens in the browser, matching the UI mockup provided.
8+
---
9+
site/src/pages/WorkspacesPage/WorkspacesTable.tsx | 4 ++--
10+
1 file changed, 2 insertions(+), 2 deletions(-)
11+
12+
diff --git a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx
13+
index 23695d8..f0a8d3f 100644
14+
--- a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx
15+
+++ b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx
16+
@@ -734,7 +734,7 @@ const WorkspaceApps: FC<WorkspaceAppsProps> = ({ workspace }) => {
17+
<BaseIconLink
18+
key="vscode"
19+
isLoading={!token}
20+
- label="Open VSCode"
21+
+ label="Open VS Code in Browser"
22+
href={getVSCodeHref("vscode", {
23+
owner: workspace.owner_name,
24+
workspace: workspace.name,
25+
@@ -752,7 +752,7 @@ const WorkspaceApps: FC<WorkspaceAppsProps> = ({ workspace }) => {
26+
buttons.push(
27+
<BaseIconLink
28+
key="vscode-insiders"
29+
- label="Open VSCode Insiders"
30+
+ label="Open VS Code Insiders in Browser"
31+
isLoading={!token}
32+
href={getVSCodeHref("vscode-insiders", {
33+
owner: workspace.owner_name,
34+
--
35+
2.43.0
36+

0 commit comments

Comments
 (0)