Skip to content

Commit 5433d0a

Browse files
committed
Refactor recent connections
- Display workspace name instead of host name. - Add deployment URL next to the workspace name. - Add IDE product and build to the connection display (partially addresses #400). - Truncate the path from the head if it is too long. - Delete invalid recent connections. - Delete connections with deleted workspaces (closes #396). - Group connections by deployment URL and then workspace name. Just a DX improvement, so we do not need to do janky things like `connections[0].name` under the assumption all the connections share the same name. Could also let us create separate sections per deployment in the future, if we need that. - Display status and errors under the workspace name instead of in a tooltip (closes #397). - Replace config and terminal link with deployment URL Both of those things can be derived from the URL. The main reason for this is that there might not be anything in the config when not using token authentication.
1 parent abe0d2f commit 5433d0a

7 files changed

+273
-104
lines changed

src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt

+1-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import com.coder.gateway.sdk.v2.models.WorkspaceStatus
3131
import com.coder.gateway.services.CoderRestClientService
3232
import com.coder.gateway.services.CoderSettingsService
3333
import com.coder.gateway.util.toURL
34-
import com.coder.gateway.util.withPath
3534
import com.coder.gateway.views.steps.CoderWorkspaceProjectIDEStepView
3635
import com.coder.gateway.views.steps.CoderWorkspacesStepSelection
3736
import com.intellij.openapi.application.ApplicationManager
@@ -179,10 +178,9 @@ class CoderGatewayConnectionProvider : GatewayConnectionProvider {
179178
projectPath = parameters.folder(),
180179
ideProductCode = parameters.ideProductCode(),
181180
ideBuildNumber = parameters.ideBuildNumber(),
182-
webTerminalLink = client.url.withPath("/@$username/$workspace.name/terminal").toString(),
183-
configDirectory = cli.coderConfigPath.toString(),
184181
idePathOnHost = parameters.idePathOnHost(),
185182
downloadSource = parameters.ideDownloadLink(),
183+
deploymentURL = deploymentURL,
186184
lastOpened = null, // Have not opened yet.
187185
)
188186
}

src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,12 @@ class CoderRemoteConnectionHandle {
8080
indicator.text = CoderGatewayBundle.message("gateway.connector.coder.connecting.failed.retry", humanizeDuration(remainingMs))
8181
},
8282
)
83-
logger.info("Deploying and starting IDE with $context")
83+
logger.info("Starting and connecting to ${parameters.ideName} with $context")
8484
// At this point JetBrains takes over with their own UI.
8585
@Suppress("UnstableApiUsage") SshDeployFlowUtil.fullDeployCycle(
8686
clientLifetime, context, Duration.ofMinutes(10)
8787
)
88+
logger.info("Adding ${parameters.ideName} for ${parameters.hostname}:${parameters.projectPath} to recent connections")
8889
recentConnectionsService.addRecentConnection(parameters.toRecentWorkspaceConnection())
8990
} catch (e: Exception) {
9091
if (isCancellation(e)) {

src/main/kotlin/com/coder/gateway/models/RecentWorkspaceConnection.kt

+9
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ class RecentWorkspaceConnection(
1717
ideBuildNumber: String? = null,
1818
downloadSource: String? = null,
1919
idePathOnHost: String? = null,
20+
// webTerminalLink and configDirectory are deprecated by deploymentURL.
2021
webTerminalLink: String? = null,
2122
configDirectory: String? = null,
2223
name: String? = null,
24+
deploymentURL: String? = null,
2325
) : BaseState(), Comparable<RecentWorkspaceConnection> {
2426
@get:Attribute
2527
var coderWorkspaceHostname by string()
@@ -35,12 +37,16 @@ class RecentWorkspaceConnection(
3537
var downloadSource by string()
3638
@get:Attribute
3739
var idePathOnHost by string()
40+
@Deprecated("Derive from deploymentURL instead.")
3841
@get:Attribute
3942
var webTerminalLink by string()
43+
@Deprecated("Derive from deploymentURL instead.")
4044
@get:Attribute
4145
var configDirectory by string()
4246
@get:Attribute
4347
var name by string()
48+
@get:Attribute
49+
var deploymentURL by string()
4450

4551
init {
4652
this.coderWorkspaceHostname = coderWorkspaceHostname
@@ -50,8 +56,11 @@ class RecentWorkspaceConnection(
5056
this.ideBuildNumber = ideBuildNumber
5157
this.downloadSource = downloadSource
5258
this.idePathOnHost = idePathOnHost
59+
@Suppress("DEPRECATION")
5360
this.webTerminalLink = webTerminalLink
61+
@Suppress("DEPRECATION")
5462
this.configDirectory = configDirectory
63+
this.deploymentURL = deploymentURL
5564
this.name = name
5665
}
5766

src/main/kotlin/com/coder/gateway/models/WorkspaceProjectIDE.kt

+27-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import com.jetbrains.gateway.ssh.deploy.TransferProgressTracker
1616
import com.jetbrains.gateway.ssh.util.validateIDEInstallPath
1717
import org.zeroturnaround.exec.ProcessExecutor
1818
import java.net.URI
19+
import java.nio.file.Path
1920
import java.time.Duration
2021
import java.time.LocalDateTime
2122
import java.time.format.DateTimeFormatter
23+
import kotlin.io.path.name
2224

2325
private val localTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MMM-dd HH:mm")
2426

@@ -266,15 +268,37 @@ class WorkspaceProjectIDE(
266268
* on a workspace. Throw if invalid.
267269
*/
268270
fun RecentWorkspaceConnection.toWorkspaceProjectIDE(): WorkspaceProjectIDE {
271+
val hostname = coderWorkspaceHostname
272+
@Suppress("DEPRECATION")
273+
val dir = configDirectory
269274
return WorkspaceProjectIDE.fromInputs(
270-
name = name,
271-
hostname = coderWorkspaceHostname,
275+
// The name was added to query the workspace status on the recent
276+
// connections page, so it could be missing. Try to get it from the
277+
// host name.
278+
name = if (name.isNullOrBlank() && !hostname.isNullOrBlank()) {
279+
hostname
280+
.removePrefix("coder-jetbrains--")
281+
.removeSuffix("--${hostname.split("--").last()}")
282+
} else name,
283+
hostname = hostname,
272284
projectPath = projectPath,
273285
ideProductCode = ideProductCode,
274286
ideBuildNumber = ideBuildNumber,
275287
idePathOnHost = idePathOnHost,
276288
downloadSource = downloadSource,
277-
deploymentURL = deploymentURL,
289+
// The deployment URL was added to replace storing the web terminal link
290+
// and config directory, as we can construct both from the URL and the
291+
// config directory might not always exist (for example, authentication
292+
// might happen with mTLS, and we can skip login which normally creates
293+
// the config directory). For backwards compatibility with existing
294+
// entries, extract the URL from the config directory or host name.
295+
deploymentURL = if (deploymentURL.isNullOrBlank()) {
296+
if (!dir.isNullOrBlank()) {
297+
"https://${Path.of(dir).parent.name}"
298+
} else if (!hostname.isNullOrBlank()) {
299+
"https://${hostname.split("--").last()}"
300+
} else deploymentURL
301+
} else deploymentURL,
278302
lastOpened = lastOpened,
279303
)
280304
}

0 commit comments

Comments
 (0)