From 66ddbf878f54e693c8d2ca84b6568466f3f0d3fc Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Mon, 20 Oct 2025 21:48:26 +0300 Subject: [PATCH 01/11] impl: ability to customize the link to workspace creation in Dashboard Some clients (Netflix in this specific case) rely on mainly their own dashboard tools instead of the Coder one. Two main reasons that were mentioned by Netflix: - aggregate many dev tools in a unified internal console - specific platform/security needs that their own UI handles better For this reason they would like the actions open up the Coder Dashboard (only Create workspace for now) to be fully customizable, and allow clients to override the URL. For `Create workspace` we now have a config that defaults $lastDeploymentUrl/templates, but it can be replaced with a relative URL to $lastDeploymentUrl or a complete new URL. For now the decision is to not allow configuration from UI since Netflix is the only target for this change, and they deploy at scale a templated settings.json. --- README.md | 6 ++++++ .../kotlin/com/coder/toolbox/CoderRemoteProvider.kt | 9 ++++++++- .../coder/toolbox/settings/ReadOnlyCoderSettings.kt | 4 ++++ .../com/coder/toolbox/store/CoderSettingsStore.kt | 3 +++ src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt | 2 ++ .../com/coder/toolbox/util/URLExtensionsTest.kt | 12 ++++++------ 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 74e9cd5..76cd82b 100644 --- a/README.md +++ b/README.md @@ -360,6 +360,12 @@ storage paths. The options can be configured from the plugin's main Workspaces p - `Header command` command that outputs additional HTTP headers. Each line of output must be in the format key=value. The environment variable CODER_URL will be available to the command process. +- `lastDeploymentURL` the last Coder deployment URL that Coder Toolbox successfully authenticated to. + +- `workspaceCreatePath` specifies the dashboard page’s relative path (to `lastDeploymentURL`) or full URL where users + can create new workspaces. Helpful for customers that have their own in-house dashboards. Defaults to `/templates` if + missing. + ### TLS settings The following options control the secure communication behavior of the plugin with Coder deployment and its available diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt index ed4854c..a08cad5 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt @@ -224,7 +224,14 @@ class CoderRemoteProvider( override val additionalPluginActions: StateFlow> = MutableStateFlow( listOf( Action(context, "Create workspace") { - context.desktop.browse(client?.url?.withPath("/templates").toString()) { + val wsCreatePath = context.settingsStore.workspaceCreatePath + val url = if (wsCreatePath.startsWith("http://") || wsCreatePath.startsWith("https://")) { + wsCreatePath + } else { + client?.url?.withPath(wsCreatePath).toString() + } + + context.desktop.browse(url) { context.ui.showErrorInfoPopup(it) } }, diff --git a/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt b/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt index 9ac6438..b63b5d6 100644 --- a/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt +++ b/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt @@ -137,6 +137,10 @@ interface ReadOnlyCoderSettings { */ val sshConfigOptions: String? + /** + * A relative path or full URL to the dashboard page used for creating workspaces. + */ + val workspaceCreatePath: String /** * The path where network information for SSH hosts are stored diff --git a/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt b/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt index 66706ca..b0b3973 100644 --- a/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt +++ b/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt @@ -80,6 +80,9 @@ class CoderSettingsStore( .normalize() .toString() + override val workspaceCreatePath: String + get() = store[WORKSPACE_CREATE_PATH] ?: "/templates" + /** * Where the specified deployment should put its data. */ diff --git a/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt b/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt index 555c6b5..9f037b3 100644 --- a/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt +++ b/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt @@ -46,5 +46,7 @@ internal const val SSH_CONFIG_OPTIONS = "sshConfigOptions" internal const val NETWORK_INFO_DIR = "networkInfoDir" +internal const val WORKSPACE_CREATE_PATH = "workspaceCreatePath" + internal const val SSH_AUTO_CONNECT_PREFIX = "ssh_auto_connect_" diff --git a/src/test/kotlin/com/coder/toolbox/util/URLExtensionsTest.kt b/src/test/kotlin/com/coder/toolbox/util/URLExtensionsTest.kt index af1b4ef..eebd424 100644 --- a/src/test/kotlin/com/coder/toolbox/util/URLExtensionsTest.kt +++ b/src/test/kotlin/com/coder/toolbox/util/URLExtensionsTest.kt @@ -9,21 +9,21 @@ internal class URLExtensionsTest { @Test fun testToURL() { assertEquals( - URL("https", "localhost", 8080, "/path"), - "https://localhost:8080/path".toURL(), + expected = URI.create("https://localhost:8080/path").toURL(), + actual = "https://localhost:8080/path".toURL(), ) } @Test fun testWithPath() { assertEquals( - URL("https", "localhost", 8080, "/foo/bar"), - URL("https", "localhost", 8080, "/").withPath("/foo/bar"), + expected = "https://localhost:8080/foo/bar".toURL(), + actual = "https://localhost:8080/".toURL().withPath("/foo/bar"), ) assertEquals( - URL("https", "localhost", 8080, "/foo/bar"), - URL("https", "localhost", 8080, "/old/path").withPath("/foo/bar"), + expected = "https://localhost:8080/foo/bar".toURL(), + actual = "https://localhost:8080/old/path".toURL().withPath("/foo/bar"), ) } From 912fbef30ff99765a0ab2f7f6281df410338fb80 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Mon, 20 Oct 2025 22:01:14 +0300 Subject: [PATCH 02/11] chore: next version is 0.7.2-alpha1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d1e72be..32c0f25 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version=0.7.1 +version=0.7.2-alpha1 group=com.coder.toolbox name=coder-toolbox \ No newline at end of file From c312ea03b97057ea65675516a5cae414a3adcef1 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Tue, 28 Oct 2025 00:20:48 +0200 Subject: [PATCH 03/11] refactor: only support full URLs There is no need to support relative paths as the existing customer will have a custom dashboard that is hosted on a different hostname than the Coder deployment. The part related to relative URL paths is now removed in order to simplify the code. --- README.md | 5 ++--- src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt | 8 +------- .../com/coder/toolbox/settings/ReadOnlyCoderSettings.kt | 4 ++-- .../kotlin/com/coder/toolbox/store/CoderSettingsStore.kt | 4 ++-- src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt | 2 +- 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 76cd82b..38d5249 100644 --- a/README.md +++ b/README.md @@ -362,9 +362,8 @@ storage paths. The options can be configured from the plugin's main Workspaces p - `lastDeploymentURL` the last Coder deployment URL that Coder Toolbox successfully authenticated to. -- `workspaceCreatePath` specifies the dashboard page’s relative path (to `lastDeploymentURL`) or full URL where users - can create new workspaces. Helpful for customers that have their own in-house dashboards. Defaults to `/templates` if - missing. +- `workspaceCreateUrl` specifies the dashboard page full URL where users can create new workspaces. + Helpful for customers that have their own in-house dashboards. Defaults to the Coder deployment templates page. ### TLS settings diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt index a08cad5..1070dc2 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt @@ -224,13 +224,7 @@ class CoderRemoteProvider( override val additionalPluginActions: StateFlow> = MutableStateFlow( listOf( Action(context, "Create workspace") { - val wsCreatePath = context.settingsStore.workspaceCreatePath - val url = if (wsCreatePath.startsWith("http://") || wsCreatePath.startsWith("https://")) { - wsCreatePath - } else { - client?.url?.withPath(wsCreatePath).toString() - } - + val url = context.settingsStore.workspaceCreateUrl ?: client?.url?.withPath("/templates").toString() context.desktop.browse(url) { context.ui.showErrorInfoPopup(it) } diff --git a/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt b/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt index b63b5d6..78e66d3 100644 --- a/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt +++ b/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt @@ -138,9 +138,9 @@ interface ReadOnlyCoderSettings { val sshConfigOptions: String? /** - * A relative path or full URL to the dashboard page used for creating workspaces. + * A custom full URL to the dashboard page used for creating workspaces. */ - val workspaceCreatePath: String + val workspaceCreateUrl: String? /** * The path where network information for SSH hosts are stored diff --git a/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt b/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt index b0b3973..421498d 100644 --- a/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt +++ b/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt @@ -80,8 +80,8 @@ class CoderSettingsStore( .normalize() .toString() - override val workspaceCreatePath: String - get() = store[WORKSPACE_CREATE_PATH] ?: "/templates" + override val workspaceCreateUrl: String? + get() = store[WORKSPACE_CREATE_URL] /** * Where the specified deployment should put its data. diff --git a/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt b/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt index 9f037b3..9692e74 100644 --- a/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt +++ b/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt @@ -46,7 +46,7 @@ internal const val SSH_CONFIG_OPTIONS = "sshConfigOptions" internal const val NETWORK_INFO_DIR = "networkInfoDir" -internal const val WORKSPACE_CREATE_PATH = "workspaceCreatePath" +internal const val WORKSPACE_CREATE_URL = "workspaceCreateUrl" internal const val SSH_AUTO_CONNECT_PREFIX = "ssh_auto_connect_" From c81f36c80a6c81f46ff6dc5ec30fa255934dafad Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Tue, 28 Oct 2025 00:39:23 +0200 Subject: [PATCH 04/11] impl: ability to customize the link to workspace details in Dashboard For `Open in dashboard` we now have a config that can be replaced with a complete new URL to another custom hostname and path. This new setting supports `$workspaceOwner` and `$workspaceName` as placeholders. --- README.md | 4 + playground.ipynb | 82 +++++++++++++++++++ .../coder/toolbox/CoderRemoteEnvironment.kt | 7 +- .../toolbox/settings/ReadOnlyCoderSettings.kt | 6 ++ .../coder/toolbox/store/CoderSettingsStore.kt | 2 + .../com/coder/toolbox/store/StoreKeys.kt | 1 + 6 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 playground.ipynb diff --git a/README.md b/README.md index 38d5249..c30b39f 100644 --- a/README.md +++ b/README.md @@ -362,6 +362,10 @@ storage paths. The options can be configured from the plugin's main Workspaces p - `lastDeploymentURL` the last Coder deployment URL that Coder Toolbox successfully authenticated to. +- `workspaceViewUrl` specifies the dashboard page full URL where users can view details about a workspace. + Helpful for customers that have their own in-house dashboards. Defaults to the Coder deployment workspace page. + This setting supports `$workspaceOwner` and `$workspaceName` as placeholders. + - `workspaceCreateUrl` specifies the dashboard page full URL where users can create new workspaces. Helpful for customers that have their own in-house dashboards. Defaults to the Coder deployment templates page. diff --git a/playground.ipynb b/playground.ipynb new file mode 100644 index 0000000..da114af --- /dev/null +++ b/playground.ipynb @@ -0,0 +1,82 @@ +{ + "cells": [ + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-13T19:21:18.748657Z", + "start_time": "2025-10-13T19:21:18.421817Z" + } + }, + "cell_type": "code", + "source": [ + "import java.net.URLEncoder\n", + "import java.nio.charset.StandardCharsets\n", + "\n", + "data class Inner(var txt: String?)\n", + "data class Outer(val inner: Inner)\n", + "\n", + "fun firstApproach() {\n", + " val o = Outer(Inner(null))\n", + " val res = listOf(\n", + " \"--begin\",\n", + " \"--acs\",\n", + " if (!o.inner.txt.isNullOrBlank()) \"--header-command\" else null,\n", + " \"--end\"\n", + " )\n", + "\n", + " println(res)\n", + "}\n", + "\n", + "fun secondApproach() {\n", + " val o = Outer(Inner(null))\n", + " val res = listOf(\n", + " \"--begin\",\n", + " \"--acs\",\n", + " o.inner.txt?.takeIf { it.isNotBlank() }?.let { \"--header-command\" },\n", + " \"--end\"\n", + " )\n", + "\n", + " println(res)\n", + "}\n", + "\n", + "firstApproach()\n", + "secondApproach()\n", + "\n", + "// https://dev.coder.com/oauth2/authorize?client_id=f8088cf1-6c3f-454a-8d48-9f86d161e845&response_type=code&code_challenge=kKhqZ3rTJwm5J1K5TSjWJ1meJXSr5Bd-fPzVBsqXdHY&redirect_uri=jetbrains://gateway/com.coder.toolbox/auth&state=d29de88b-c54d-4e2a-9de0-685b554895ed&code_challenge_method=S256\n", + "\n", + "\"jetbrains://gateway/com.coder.toolbox/oauth\"\n", + "println(URLEncoder.encode(\"jetbrains://gateway/com.coder.toolbox/oauth\", StandardCharsets.UTF_8.toString()))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[--begin, --acs, null, --end]\n", + "[--begin, --acs, null, --end]\n", + "jetbrains%3A%2F%2Fgateway%2Fcom.coder.toolbox%2Foauth\n" + ] + } + ], + "execution_count": 1 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Kotlin", + "language": "kotlin", + "name": "kotlin" + }, + "language_info": { + "name": "kotlin", + "version": "1.9.23", + "mimetype": "text/x-kotlin", + "file_extension": ".kt", + "pygments_lexer": "kotlin", + "codemirror_mode": "text/x-kotlin", + "nbconvert_exporter": "" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt index 5bb4296..2bbf374 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt @@ -91,8 +91,13 @@ class CoderRemoteEnvironment( } actions.add( Action(context, "Open in dashboard") { + val urlTemplate = context.settingsStore.workspaceViewUrl + ?: client.url.withPath("/@${workspace.ownerName}/${workspace.name}").toString() + val url = urlTemplate + .replace("\$workspaceOwner", "@${workspace.ownerName}") + .replace("\$workspaceName", workspace.name) context.desktop.browse( - client.url.withPath("/@${workspace.ownerName}/${workspace.name}").toString() + url ) { context.ui.showErrorInfoPopup(it) } diff --git a/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt b/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt index 78e66d3..e187885 100644 --- a/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt +++ b/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt @@ -137,6 +137,12 @@ interface ReadOnlyCoderSettings { */ val sshConfigOptions: String? + /** + * A custom full URL to the dashboard page used for viewing details about a workspace. + * Supports `$workspaceOwner` and `$workspaceName` as placeholders. + */ + val workspaceViewUrl: String? + /** * A custom full URL to the dashboard page used for creating workspaces. */ diff --git a/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt b/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt index 421498d..becdea0 100644 --- a/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt +++ b/src/main/kotlin/com/coder/toolbox/store/CoderSettingsStore.kt @@ -80,6 +80,8 @@ class CoderSettingsStore( .normalize() .toString() + override val workspaceViewUrl: String? + get() = store[WORKSPACE_VIEW_URL] override val workspaceCreateUrl: String? get() = store[WORKSPACE_CREATE_URL] diff --git a/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt b/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt index 9692e74..d38631a 100644 --- a/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt +++ b/src/main/kotlin/com/coder/toolbox/store/StoreKeys.kt @@ -46,6 +46,7 @@ internal const val SSH_CONFIG_OPTIONS = "sshConfigOptions" internal const val NETWORK_INFO_DIR = "networkInfoDir" +internal const val WORKSPACE_VIEW_URL = "workspaceViewUrl" internal const val WORKSPACE_CREATE_URL = "workspaceCreateUrl" internal const val SSH_AUTO_CONNECT_PREFIX = "ssh_auto_connect_" From cf222f9d960984570361a023bb6bfd3670c26de6 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Tue, 28 Oct 2025 22:16:55 +0200 Subject: [PATCH 05/11] chore: next version is 0.7.3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 32c0f25..2c53740 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version=0.7.2-alpha1 +version=0.7.3 group=com.coder.toolbox name=coder-toolbox \ No newline at end of file From 9923a8bae096a99bbc5cd8f31d2dcd665cf05bf0 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Tue, 28 Oct 2025 22:26:43 +0200 Subject: [PATCH 06/11] chore: remove playground file --- playground.ipynb | 82 ------------------------------------------------ 1 file changed, 82 deletions(-) delete mode 100644 playground.ipynb diff --git a/playground.ipynb b/playground.ipynb deleted file mode 100644 index da114af..0000000 --- a/playground.ipynb +++ /dev/null @@ -1,82 +0,0 @@ -{ - "cells": [ - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-10-13T19:21:18.748657Z", - "start_time": "2025-10-13T19:21:18.421817Z" - } - }, - "cell_type": "code", - "source": [ - "import java.net.URLEncoder\n", - "import java.nio.charset.StandardCharsets\n", - "\n", - "data class Inner(var txt: String?)\n", - "data class Outer(val inner: Inner)\n", - "\n", - "fun firstApproach() {\n", - " val o = Outer(Inner(null))\n", - " val res = listOf(\n", - " \"--begin\",\n", - " \"--acs\",\n", - " if (!o.inner.txt.isNullOrBlank()) \"--header-command\" else null,\n", - " \"--end\"\n", - " )\n", - "\n", - " println(res)\n", - "}\n", - "\n", - "fun secondApproach() {\n", - " val o = Outer(Inner(null))\n", - " val res = listOf(\n", - " \"--begin\",\n", - " \"--acs\",\n", - " o.inner.txt?.takeIf { it.isNotBlank() }?.let { \"--header-command\" },\n", - " \"--end\"\n", - " )\n", - "\n", - " println(res)\n", - "}\n", - "\n", - "firstApproach()\n", - "secondApproach()\n", - "\n", - "// https://dev.coder.com/oauth2/authorize?client_id=f8088cf1-6c3f-454a-8d48-9f86d161e845&response_type=code&code_challenge=kKhqZ3rTJwm5J1K5TSjWJ1meJXSr5Bd-fPzVBsqXdHY&redirect_uri=jetbrains://gateway/com.coder.toolbox/auth&state=d29de88b-c54d-4e2a-9de0-685b554895ed&code_challenge_method=S256\n", - "\n", - "\"jetbrains://gateway/com.coder.toolbox/oauth\"\n", - "println(URLEncoder.encode(\"jetbrains://gateway/com.coder.toolbox/oauth\", StandardCharsets.UTF_8.toString()))" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[--begin, --acs, null, --end]\n", - "[--begin, --acs, null, --end]\n", - "jetbrains%3A%2F%2Fgateway%2Fcom.coder.toolbox%2Foauth\n" - ] - } - ], - "execution_count": 1 - } - ], - "metadata": { - "kernelspec": { - "display_name": "Kotlin", - "language": "kotlin", - "name": "kotlin" - }, - "language_info": { - "name": "kotlin", - "version": "1.9.23", - "mimetype": "text/x-kotlin", - "file_extension": ".kt", - "pygments_lexer": "kotlin", - "codemirror_mode": "text/x-kotlin", - "nbconvert_exporter": "" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} From 81467c1641d2c478e0a8ee55c41770a5997778a4 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Thu, 30 Oct 2025 01:29:43 +0200 Subject: [PATCH 07/11] fix: discard @ from workspaceOwner placeholder --- src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt index 2bbf374..ff413c5 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt @@ -94,7 +94,7 @@ class CoderRemoteEnvironment( val urlTemplate = context.settingsStore.workspaceViewUrl ?: client.url.withPath("/@${workspace.ownerName}/${workspace.name}").toString() val url = urlTemplate - .replace("\$workspaceOwner", "@${workspace.ownerName}") + .replace("\$workspaceOwner", "${workspace.ownerName}") .replace("\$workspaceName", workspace.name) context.desktop.browse( url From 45cabcd731c068f0a6cd0b44d6e40baa2586fcff Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Thu, 30 Oct 2025 01:30:39 +0200 Subject: [PATCH 08/11] impl: support $workspaceOwner as placeholder in the workspace creation Should be replaced with the name of the user that is authenticated. --- src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt index 1070dc2..300f5a9 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt @@ -225,7 +225,10 @@ class CoderRemoteProvider( listOf( Action(context, "Create workspace") { val url = context.settingsStore.workspaceCreateUrl ?: client?.url?.withPath("/templates").toString() - context.desktop.browse(url) { + context.desktop.browse( + url + .replace("\$workspaceOwner", client?.me()?.username ?: "") + ) { context.ui.showErrorInfoPopup(it) } }, From bfd7530c2877a081709b2b851cbba3bb52998d44 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Thu, 30 Oct 2025 01:40:13 +0200 Subject: [PATCH 09/11] doc: improved description for `workspaceCreateUrl` setting --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2c53740..5d2d978 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version=0.7.3 +version=0.7.2-alpha3 group=com.coder.toolbox name=coder-toolbox \ No newline at end of file From c85e2b8ba79564391445307af5b1612fcd931759 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Thu, 30 Oct 2025 01:43:36 +0200 Subject: [PATCH 10/11] doc: improved description for `workspaceCreateUrl` setting (2) --- README.md | 1 + gradle.properties | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c30b39f..2d50806 100644 --- a/README.md +++ b/README.md @@ -368,6 +368,7 @@ storage paths. The options can be configured from the plugin's main Workspaces p - `workspaceCreateUrl` specifies the dashboard page full URL where users can create new workspaces. Helpful for customers that have their own in-house dashboards. Defaults to the Coder deployment templates page. + This setting supports `$workspaceOwner` as placeholder with the replacing value being the username that logged in. ### TLS settings diff --git a/gradle.properties b/gradle.properties index 5d2d978..2c53740 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version=0.7.2-alpha3 +version=0.7.3 group=com.coder.toolbox name=coder-toolbox \ No newline at end of file From 5cde8474ec672effaaa7b759c14a458da271722f Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Thu, 30 Oct 2025 01:47:11 +0200 Subject: [PATCH 11/11] chore: update code documentation --- .../kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt b/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt index e187885..8eed699 100644 --- a/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt +++ b/src/main/kotlin/com/coder/toolbox/settings/ReadOnlyCoderSettings.kt @@ -145,6 +145,7 @@ interface ReadOnlyCoderSettings { /** * A custom full URL to the dashboard page used for creating workspaces. + * Supports `$workspaceOwner` as placeholder. */ val workspaceCreateUrl: String?