Skip to content

Commit 52ea852

Browse files
committed
Read URL and token from config on launch
In case the user has already configured the CLI. This will only happen until the first succesful connection. Additionally, add a "use existing token" checkbox which will both not open the browser window and will also read from the config if the token matches the URL we are trying to open. Lastly I removed some padding in an attempt to regain the space lost by the additions.
1 parent f51b551 commit 52ea852

File tree

3 files changed

+86
-10
lines changed

3 files changed

+86
-10
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ data class CoderWorkspacesWizardModel(
55
var token: String = "",
66
var buildVersion: String = "",
77
var localCliPath: String = "",
8-
var selectedWorkspace: WorkspaceAgentModel? = null
9-
)
8+
var selectedWorkspace: WorkspaceAgentModel? = null,
9+
var useExistingToken: Boolean = false
10+
)

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

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,12 @@ import java.awt.event.MouseListener
7676
import java.awt.event.MouseMotionListener
7777
import java.awt.font.TextAttribute
7878
import java.awt.font.TextAttribute.UNDERLINE_ON
79+
import java.nio.file.Files
80+
import java.nio.file.Path
81+
import java.nio.file.Paths
7982
import java.net.SocketTimeoutException
8083
import javax.swing.Icon
84+
import javax.swing.JCheckBox
8185
import javax.swing.JTable
8286
import javax.swing.JTextField
8387
import javax.swing.ListSelectionModel
@@ -100,6 +104,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
100104
private val appPropertiesService: PropertiesComponent = service()
101105

102106
private var tfUrl: JTextField? = null
107+
private var cbExistingToken: JCheckBox? = null
103108
private var listTableModelOfWorkspaces = ListTableModel<WorkspaceAgentModel>(
104109
WorkspaceIconColumnInfo(""),
105110
WorkspaceNameColumnInfo("Name"),
@@ -201,13 +206,13 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
201206
font = JBFont.h3().asBold()
202207
icon = CoderIcons.LOGO_16
203208
}
204-
}.topGap(TopGap.SMALL).bottomGap(BottomGap.MEDIUM)
209+
}.topGap(TopGap.SMALL)
205210
row {
206211
cell(ComponentPanelBuilder.createCommentComponent(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.comment"), false, -1, true))
207212
}
208213
row {
209214
browserLink(CoderGatewayBundle.message("gateway.connector.view.login.documentation.action"), "https://coder.com/docs/coder-oss/latest/workspaces")
210-
}.bottomGap(BottomGap.MEDIUM)
215+
}
211216
row(CoderGatewayBundle.message("gateway.connector.view.login.url.label")) {
212217
tfUrl = textField().resizableColumn().align(AlignX.FILL).gap(RightGap.SMALL).bindText(localWizardModel::coderURL).applyToComponent {
213218
addActionListener {
@@ -223,6 +228,17 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
223228
}
224229
cell()
225230
}
231+
row {
232+
cbExistingToken = checkBox(CoderGatewayBundle.message("gateway.connector.view.login.existing-token.label"))
233+
.bindSelected(localWizardModel::useExistingToken)
234+
.component
235+
}
236+
row {
237+
cell(ComponentPanelBuilder.createCommentComponent(
238+
CoderGatewayBundle.message("gateway.connector.view.login.existing-token.tooltip",
239+
CoderGatewayBundle.message("gateway.connector.view.login.existing-token.label")),
240+
false, -1, true))
241+
}
226242
row {
227243
scrollCell(toolbar.createPanel().apply {
228244
add(notificationBanner.component.apply { isVisible = false }, "South")
@@ -313,18 +329,70 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
313329
if (localWizardModel.coderURL.isNotBlank() && localWizardModel.token.isNotBlank()) {
314330
triggerWorkspacePolling()
315331
} else {
316-
val url = appPropertiesService.getValue(CODER_URL_KEY)
317-
val token = appPropertiesService.getValue(SESSION_TOKEN)
318-
if (!url.isNullOrBlank() && !token.isNullOrBlank()) {
332+
val (url, token) = readStorageOrConfig()
333+
if (!url.isNullOrBlank()) {
319334
localWizardModel.coderURL = url
320-
localWizardModel.token = token
321335
tfUrl?.text = url
336+
}
337+
if (!token.isNullOrBlank()) {
338+
localWizardModel.token = token
339+
}
340+
if (!url.isNullOrBlank() && !token.isNullOrBlank()) {
322341
loginAndLoadWorkspace(token, true)
323342
}
324343
}
325344
updateWorkspaceActions()
326345
}
327346

347+
/**
348+
* Return the URL and token from storage or the CLI config.
349+
*/
350+
private fun readStorageOrConfig(): Pair<String?, String?> {
351+
val url = appPropertiesService.getValue(CODER_URL_KEY)
352+
val token = appPropertiesService.getValue(SESSION_TOKEN)
353+
if (!url.isNullOrBlank() && !token.isNullOrBlank()) {
354+
return url to token
355+
}
356+
return readConfig()
357+
}
358+
359+
/**
360+
* Return the URL and token from the CLI config.
361+
*/
362+
private fun readConfig(): Pair<String?, String?> {
363+
val configDir = getConfigDir()
364+
try {
365+
val url = Files.readString(configDir.resolve("url"))
366+
val token = Files.readString(configDir.resolve("session"))
367+
return url to token
368+
} catch (e: Exception) {
369+
return null to null // Probably has not configured the CLI yet.
370+
}
371+
}
372+
373+
/**
374+
* Return the config directory used by the CLI.
375+
*/
376+
private fun getConfigDir(): Path {
377+
var dir = System.getenv("CODER_CONFIG_DIR")
378+
if (!dir.isNullOrBlank()) {
379+
return Path.of(dir)
380+
}
381+
// The Coder CLI uses https://github.com/kirsle/configdir so this should
382+
// match how it behaves.
383+
return when(getOS()) {
384+
OS.WINDOWS -> Paths.get(System.getenv("APPDATA"), "coderv2")
385+
OS.MAC -> Paths.get(System.getenv("HOME"), "Library/Application Support/coderv2")
386+
else -> {
387+
dir = System.getenv("XDG_CACHE_HOME")
388+
if (!dir.isNullOrBlank()) {
389+
return Paths.get(dir, "coderv2")
390+
}
391+
return Paths.get(System.getenv("HOME"), ".config/coderv2")
392+
}
393+
}
394+
}
395+
328396
private fun updateWorkspaceActions() {
329397
goToDashboardAction.isEnabled = coderClient.isReady
330398
createWorkspaceAction.isEnabled = coderClient.isReady
@@ -440,8 +508,13 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
440508

441509
private fun askToken(openBrowser: Boolean): String? {
442510
val getTokenUrl = localWizardModel.coderURL.toURL().withPath("/login?redirect=%2Fcli-auth")
443-
if (openBrowser) {
511+
if (openBrowser && !localWizardModel.useExistingToken) {
444512
BrowserUtil.browse(getTokenUrl)
513+
} else if (localWizardModel.useExistingToken) {
514+
val (url, token) = readConfig()
515+
if (url == localWizardModel.coderURL && !token.isNullOrBlank()) {
516+
localWizardModel.token = token
517+
}
445518
}
446519
var tokenFromUser: String? = null
447520
ApplicationManager.getApplication().invokeAndWait({

src/main/resources/messages/CoderGatewayBundle.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ gateway.connector.description=Connects to a Coder Workspace dev environment so t
33
gateway.connector.action.text=Connect to Coder
44
gateway.connector.view.login.documentation.action=Learn more about Coder
55
gateway.connector.view.login.url.label=URL:
6+
gateway.connector.view.login.existing-token.label=Use existing token
7+
gateway.connector.view.login.existing-token.tooltip=Checking "{0}" will prevent the browser from automatically being launched for generating a token. Additionally, if there is a token already configured on disk for this URL via the CLI it will be used automatically.
68
gateway.connector.view.login.token.dialog=Paste your token here:
79
gateway.connector.view.login.token.label=Session Token:
810
gateway.connector.view.coder.workspaces.header.text=Coder Workspaces
@@ -28,4 +30,4 @@ gateway.connector.recentconnections.title=Recent Coder Workspaces
2830
gateway.connector.recentconnections.new.wizard.button.tooltip=Open a new Coder Workspace
2931
gateway.connector.recentconnections.remove.button.tooltip=Remove from Recent Connections
3032
gateway.connector.recentconnections.terminal.button.tooltip=Open SSH Web Terminal
31-
gateway.connector.coder.connection.provider.title=Connecting to Coder workspace...
33+
gateway.connector.coder.connection.provider.title=Connecting to Coder workspace...

0 commit comments

Comments
 (0)