Skip to content

Commit 708bc6b

Browse files
authored
fix: pass the folder parameter to the IDE&Project dialog (#550)
* chore: use newer snapshot build for testing and building I've also changed the list of Gateway versions we run the verifier against to include Gateway 2025.1 while excluding some ancient releases. Without this commit the PR will fail to build, the declared snapshots are no longer available in the repository * fix: pass the folder parameter to the IDE&Project dialog The value of the `folder` URI parameter is passed to the IDE&Project dialog when handling URIs. The folder value will be rendered instead of the default home folder if the value is not blank. -resolves #466 * chore: next version is 2.20.1
1 parent 79118e3 commit 708bc6b

File tree

6 files changed

+80
-37
lines changed

6 files changed

+80
-37
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
### Fixed
1212

1313
- installed EAP, RC, NIGHTLY and PREVIEW IDEs are no longer displayed if there is a higher released version available for download.
14+
- project path is prefilled with the `folder` URI parameter when the IDE&Project dialog opens for URI handling.
1415

1516
## 2.19.0 - 2025-02-21
1617

gradle.properties

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ pluginGroup=com.coder.gateway
44
# Zip file name.
55
pluginName=coder-gateway
66
# SemVer format -> https://semver.org
7-
pluginVersion=2.20.0
7+
pluginVersion=2.20.1
88
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
99
# for insight into build numbers and IntelliJ Platform versions.
10-
pluginSinceBuild=233.6745
10+
pluginSinceBuild=243.26053
1111
# This should be kept up to date with the latest EAP. If the API is incompatible
1212
# with the latest stable, use the eap branch temporarily instead.
1313
pluginUntilBuild=251.*
@@ -26,11 +26,11 @@ pluginUntilBuild=251.*
2626
# that exists, ideally the most recent one, for example
2727
# 233.15325-EAP-CANDIDATE-SNAPSHOT).
2828
platformType=GW
29-
platformVersion=241.19416-EAP-CANDIDATE-SNAPSHOT
30-
instrumentationCompiler=243.15521-EAP-CANDIDATE-SNAPSHOT
29+
platformVersion=243.26053-EAP-CANDIDATE-SNAPSHOT
30+
instrumentationCompiler=243.26053-EAP-CANDIDATE-SNAPSHOT
3131
# Gateway does not have open sources.
3232
platformDownloadSources=true
33-
verifyVersions=2023.3,2024.1,2024.2,2024.3
33+
verifyVersions=2024.3,2025.1
3434
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
3535
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
3636
platformPlugins=

src/main/kotlin/com/coder/gateway/util/Dialogs.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ private class CoderWorkspaceStepDialog(
3838

3939
init {
4040
init()
41-
title = CoderGatewayBundle.message("gateway.connector.view.coder.remoteproject.choose.text", CoderCLIManager.getWorkspaceParts(state.workspace, state.agent))
41+
title = CoderGatewayBundle.message(
42+
"gateway.connector.view.coder.remoteproject.choose.text",
43+
CoderCLIManager.getWorkspaceParts(state.workspace, state.agent)
44+
)
4245
}
4346

4447
override fun show() {
@@ -75,12 +78,13 @@ fun askIDE(
7578
cli: CoderCLIManager,
7679
client: CoderRestClient,
7780
workspaces: List<Workspace>,
81+
remoteProjectPath: String? = null
7882
): WorkspaceProjectIDE? {
7983
var data: WorkspaceProjectIDE? = null
8084
ApplicationManager.getApplication().invokeAndWait {
8185
val dialog =
8286
CoderWorkspaceStepDialog(
83-
CoderWorkspacesStepSelection(agent, workspace, cli, client, workspaces),
87+
CoderWorkspacesStepSelection(agent, workspace, cli, client, workspaces, remoteProjectPath),
8488
)
8589
data = dialog.showAndGetData()
8690
}

src/main/kotlin/com/coder/gateway/util/LinkHandler.kt

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ open class LinkHandler(
3232
parameters: Map<String, String>,
3333
indicator: ((t: String) -> Unit)? = null,
3434
): WorkspaceProjectIDE {
35-
val deploymentURL = parameters.url() ?: dialogUi.ask("Deployment URL", "Enter the full URL of your Coder deployment")
35+
val deploymentURL =
36+
parameters.url() ?: dialogUi.ask("Deployment URL", "Enter the full URL of your Coder deployment")
3637
if (deploymentURL.isNullOrBlank()) {
3738
throw MissingArgumentException("Query parameter \"$URL\" is missing")
3839
}
@@ -50,7 +51,8 @@ open class LinkHandler(
5051
}
5152

5253
// TODO: Show a dropdown and ask for the workspace if missing.
53-
val workspaceName = parameters.workspace() ?: throw MissingArgumentException("Query parameter \"$WORKSPACE\" is missing")
54+
val workspaceName =
55+
parameters.workspace() ?: throw MissingArgumentException("Query parameter \"$WORKSPACE\" is missing")
5456

5557
// The owner was added to support getting into another user's workspace
5658
// but may not exist if the Coder Gateway module is out of date. If no
@@ -65,9 +67,9 @@ open class LinkHandler(
6567
indicator,
6668
)
6769

68-
var workspace : Workspace
69-
var workspaces : List<Workspace> = emptyList()
70-
var workspacesAndAgents : Set<Pair<Workspace, WorkspaceAgent>> = emptySet()
70+
var workspace: Workspace
71+
var workspaces: List<Workspace> = emptyList()
72+
var workspacesAndAgents: Set<Pair<Workspace, WorkspaceAgent>> = emptySet()
7173
if (cli.features.wildcardSSH) {
7274
workspace = client.workspaceByOwnerAndName(owner, workspaceName)
7375
} else {
@@ -83,19 +85,28 @@ open class LinkHandler(
8385
WorkspaceStatus.PENDING, WorkspaceStatus.STARTING ->
8486
// TODO: Wait for the workspace to turn on.
8587
throw IllegalArgumentException(
86-
"The workspace \"$workspaceName\" is ${workspace.latestBuild.status.toString().lowercase()}; please wait then try again",
88+
"The workspace \"$workspaceName\" is ${
89+
workspace.latestBuild.status.toString().lowercase()
90+
}; please wait then try again",
8791
)
92+
8893
WorkspaceStatus.STOPPING, WorkspaceStatus.STOPPED,
8994
WorkspaceStatus.CANCELING, WorkspaceStatus.CANCELED,
90-
->
95+
->
9196
// TODO: Turn on the workspace.
9297
throw IllegalArgumentException(
93-
"The workspace \"$workspaceName\" is ${workspace.latestBuild.status.toString().lowercase()}; please start the workspace and try again",
98+
"The workspace \"$workspaceName\" is ${
99+
workspace.latestBuild.status.toString().lowercase()
100+
}; please start the workspace and try again",
94101
)
102+
95103
WorkspaceStatus.FAILED, WorkspaceStatus.DELETING, WorkspaceStatus.DELETED ->
96104
throw IllegalArgumentException(
97-
"The workspace \"$workspaceName\" is ${workspace.latestBuild.status.toString().lowercase()}; unable to connect",
105+
"The workspace \"$workspaceName\" is ${
106+
workspace.latestBuild.status.toString().lowercase()
107+
}; unable to connect",
98108
)
109+
99110
WorkspaceStatus.RUNNING -> Unit // All is well
100111
}
101112

@@ -106,10 +117,16 @@ open class LinkHandler(
106117
if (status.pending()) {
107118
// TODO: Wait for the agent to be ready.
108119
throw IllegalArgumentException(
109-
"The agent \"${agent.name}\" has a status of \"${status.toString().lowercase()}\"; please wait then try again",
120+
"The agent \"${agent.name}\" has a status of \"${
121+
status.toString().lowercase()
122+
}\"; please wait then try again",
110123
)
111124
} else if (!status.ready()) {
112-
throw IllegalArgumentException("The agent \"${agent.name}\" has a status of \"${status.toString().lowercase()}\"; unable to connect")
125+
throw IllegalArgumentException(
126+
"The agent \"${agent.name}\" has a status of \"${
127+
status.toString().lowercase()
128+
}\"; unable to connect"
129+
)
113130
}
114131

115132
// We only need to log in if we are using token-based auth.
@@ -123,12 +140,13 @@ open class LinkHandler(
123140

124141
val openDialog =
125142
parameters.ideProductCode().isNullOrBlank() ||
126-
parameters.ideBuildNumber().isNullOrBlank() ||
127-
(parameters.idePathOnHost().isNullOrBlank() && parameters.ideDownloadLink().isNullOrBlank()) ||
128-
parameters.folder().isNullOrBlank()
143+
parameters.ideBuildNumber().isNullOrBlank() ||
144+
(parameters.idePathOnHost().isNullOrBlank() && parameters.ideDownloadLink().isNullOrBlank()) ||
145+
parameters.folder().isNullOrBlank()
129146

130147
return if (openDialog) {
131-
askIDE(agent, workspace, cli, client, workspaces) ?: throw MissingArgumentException("IDE selection aborted; unable to connect")
148+
askIDE(agent, workspace, cli, client, workspaces, parameters.folder())
149+
?: throw MissingArgumentException("IDE selection aborted; unable to connect")
132150
} else {
133151
// Check that both the domain and the redirected domain are
134152
// allowlisted. If not, check with the user whether to proceed.
@@ -259,7 +277,7 @@ private fun isAllowlisted(url: URL): Triple<Boolean, Boolean, String> {
259277

260278
val allowlisted =
261279
domainAllowlist.any { url.host == it || url.host.endsWith(".$it") } &&
262-
domainAllowlist.any { finalUrl.host == it || finalUrl.host.endsWith(".$it") }
280+
domainAllowlist.any { finalUrl.host == it || finalUrl.host.endsWith(".$it") }
263281
val https = url.protocol == "https" && finalUrl.protocol == "https"
264282
return Triple(allowlisted, https, linkWithRedirect)
265283
}

src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ private fun displayIdeWithStatus(ideWithStatus: IdeWithStatus): String =
9595
* to select an IDE and project to run on the workspace.
9696
*/
9797
class CoderWorkspaceProjectIDEStepView(
98-
private val showTitle: Boolean = true,
98+
private val showTitle: Boolean = true
9999
) : CoderWizardStep<WorkspaceProjectIDE>(
100100
CoderGatewayBundle.message("gateway.connector.view.coder.remoteproject.next.text"),
101101
) {
@@ -200,7 +200,9 @@ class CoderWorkspaceProjectIDEStepView(
200200
val name = CoderCLIManager.getWorkspaceParts(data.workspace, data.agent)
201201
logger.info("Initializing workspace step for $name")
202202

203-
val homeDirectory = data.agent.expandedDirectory ?: data.agent.directory
203+
val homeDirectory = data.remoteProjectPath.takeIf { !it.isNullOrBlank() }
204+
?: data.agent.expandedDirectory
205+
?: data.agent.directory
204206
tfProject.text = if (homeDirectory.isNullOrBlank()) "/home" else homeDirectory
205207
titleLabel.text = CoderGatewayBundle.message("gateway.connector.view.coder.remoteproject.choose.text", name)
206208
titleLabel.isVisible = showTitle
@@ -429,7 +431,7 @@ class CoderWorkspaceProjectIDEStepView(
429431
if (remainingInstalledIdes.size < installedIdes.size) {
430432
logger.info(
431433
"Skipping the following list of installed IDEs because there is already a released version " +
432-
"available for download: ${(installedIdes - remainingInstalledIdes).joinToString { "${it.product.productCode} ${it.presentableVersion}" }}"
434+
"available for download: ${(installedIdes - remainingInstalledIdes).joinToString { "${it.product.productCode} ${it.presentableVersion}" }}"
433435
)
434436
}
435437
return remainingInstalledIdes.map { it.toIdeWithStatus() }.sorted() + availableIdes.map { it.toIdeWithStatus() }

src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ data class CoderWorkspacesStepSelection(
105105
// Pass along the latest workspaces so we can configure the CLI a bit
106106
// faster, otherwise this step would have to fetch the workspaces again.
107107
val workspaces: List<Workspace>,
108+
val remoteProjectPath: String? = null
108109
)
109110

110111
/**
@@ -147,7 +148,8 @@ class CoderWorkspacesStepView :
147148
setEmptyState(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.disconnected"))
148149
setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
149150
selectionModel.addListSelectionListener {
150-
nextButton.isEnabled = selectedObject?.status?.ready() == true && selectedObject?.agent?.operatingSystem == OS.LINUX
151+
nextButton.isEnabled =
152+
selectedObject?.status?.ready() == true && selectedObject?.agent?.operatingSystem == OS.LINUX
151153
if (selectedObject?.status?.ready() == true && selectedObject?.agent?.operatingSystem != OS.LINUX) {
152154
notificationBanner.apply {
153155
component.isVisible = true
@@ -343,22 +345,26 @@ class CoderWorkspacesStepView :
343345
val maxWait = Duration.ofMinutes(10)
344346
while (isActive) { // Wait for the workspace to fully stop.
345347
delay(timeout.toMillis())
346-
val found = tableOfWorkspaces.items.firstOrNull { it.workspace.id == workspace.id }
348+
val found =
349+
tableOfWorkspaces.items.firstOrNull { it.workspace.id == workspace.id }
347350
when (val status = found?.workspace?.latestBuild?.status) {
348351
WorkspaceStatus.PENDING, WorkspaceStatus.STOPPING, WorkspaceStatus.RUNNING -> {
349352
logger.info("Still waiting for ${workspace.name} to stop before updating")
350353
}
354+
351355
WorkspaceStatus.STARTING, WorkspaceStatus.FAILED,
352356
WorkspaceStatus.CANCELING, WorkspaceStatus.CANCELED,
353357
WorkspaceStatus.DELETING, WorkspaceStatus.DELETED,
354-
-> {
358+
-> {
355359
logger.warn("Canceled ${workspace.name} update due to status change to $status")
356360
break
357361
}
362+
358363
null -> {
359364
logger.warn("Canceled ${workspace.name} update because it no longer exists")
360365
break
361366
}
367+
362368
WorkspaceStatus.STOPPED -> {
363369
logger.info("${workspace.name} has stopped; updating now")
364370
c.updateWorkspace(workspace)
@@ -560,7 +566,10 @@ class CoderWorkspacesStepView :
560566
deploymentURL.host,
561567
)
562568
tableOfWorkspaces.setEmptyState(
563-
CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connecting", deploymentURL.host),
569+
CoderGatewayBundle.message(
570+
"gateway.connector.view.coder.workspaces.connect.text.connecting",
571+
deploymentURL.host
572+
),
564573
)
565574

566575
tableOfWorkspaces.listTableModel.items = emptyList()
@@ -600,7 +609,10 @@ class CoderWorkspacesStepView :
600609
client = authedClient
601610

602611
tableOfWorkspaces.setEmptyState(
603-
CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connected", deploymentURL.host),
612+
CoderGatewayBundle.message(
613+
"gateway.connector.view.coder.workspaces.connect.text.connected",
614+
deploymentURL.host
615+
),
604616
)
605617
tfUrlComment?.text =
606618
CoderGatewayBundle.message(
@@ -788,7 +800,8 @@ class WorkspacesTableModel :
788800
WorkspaceVersionColumnInfo("Version"),
789801
WorkspaceStatusColumnInfo("Status"),
790802
) {
791-
private class WorkspaceIconColumnInfo(columnName: String) : ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
803+
private class WorkspaceIconColumnInfo(columnName: String) :
804+
ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
792805
override fun valueOf(item: WorkspaceAgentListModel?): String? = item?.workspace?.templateName
793806

794807
override fun getRenderer(item: WorkspaceAgentListModel?): TableCellRenderer {
@@ -820,7 +833,8 @@ class WorkspacesTableModel :
820833
}
821834
}
822835

823-
private class WorkspaceNameColumnInfo(columnName: String) : ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
836+
private class WorkspaceNameColumnInfo(columnName: String) :
837+
ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
824838
override fun valueOf(item: WorkspaceAgentListModel?): String? = item?.name
825839

826840
override fun getComparator(): Comparator<WorkspaceAgentListModel> = Comparator { a, b ->
@@ -850,7 +864,8 @@ class WorkspacesTableModel :
850864
}
851865
}
852866

853-
private class WorkspaceOwnerColumnInfo(columnName: String) : ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
867+
private class WorkspaceOwnerColumnInfo(columnName: String) :
868+
ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
854869
override fun valueOf(item: WorkspaceAgentListModel?): String? = item?.workspace?.ownerName
855870

856871
override fun getComparator(): Comparator<WorkspaceAgentListModel> = Comparator { a, b ->
@@ -880,7 +895,8 @@ class WorkspacesTableModel :
880895
}
881896
}
882897

883-
private class WorkspaceTemplateNameColumnInfo(columnName: String) : ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
898+
private class WorkspaceTemplateNameColumnInfo(columnName: String) :
899+
ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
884900
override fun valueOf(item: WorkspaceAgentListModel?): String? = item?.workspace?.templateName
885901

886902
override fun getComparator(): java.util.Comparator<WorkspaceAgentListModel> = Comparator { a, b ->
@@ -909,7 +925,8 @@ class WorkspacesTableModel :
909925
}
910926
}
911927

912-
private class WorkspaceVersionColumnInfo(columnName: String) : ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
928+
private class WorkspaceVersionColumnInfo(columnName: String) :
929+
ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
913930
override fun valueOf(workspace: WorkspaceAgentListModel?): String? = if (workspace == null) {
914931
"Unknown"
915932
} else if (workspace.workspace.outdated) {
@@ -940,7 +957,8 @@ class WorkspacesTableModel :
940957
}
941958
}
942959

943-
private class WorkspaceStatusColumnInfo(columnName: String) : ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
960+
private class WorkspaceStatusColumnInfo(columnName: String) :
961+
ColumnInfo<WorkspaceAgentListModel, String>(columnName) {
944962
override fun valueOf(item: WorkspaceAgentListModel?): String? = item?.status?.label
945963

946964
override fun getComparator(): java.util.Comparator<WorkspaceAgentListModel> = Comparator { a, b ->

0 commit comments

Comments
 (0)