Skip to content

Cache Coder session #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,30 @@

## [Unreleased]

### Added

- support for remembering last opened Coder session

### Changed

- minimum supported Gateway build is now 222.3739.54
- some dialog titles

## [2.1.0]
### Added
- support for displaying workspace version
- support for managing the lifecycle of a workspace, i.e. start and stop and update workspace to the latest template version

### Changed
- workspace panel is now updated every 5 seconds
- combinations of workspace names and agent names are now listed even when a workspace is down
- minimum supported Gateway build is now 222.3739.40
### Added

- support for displaying workspace version
- support for managing the lifecycle of a workspace, i.e. start and stop and update workspace to the latest template version

### Changed

- workspace panel is now updated every 5 seconds
- combinations of workspace names and agent names are now listed even when a workspace is down
- minimum supported Gateway build is now 222.3739.40

### Fixed
- terminal link for workspaces with a single agent
### Fixed
- terminal link for workspaces with a single agent
- no longer allow users to open a connection to a Windows or macOS workspace. It's not yet supported by Gateway

## [2.0.2]
Expand Down
8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
pluginGroup=com.coder.gateway
pluginName=coder-gateway
# SemVer format -> https://semver.org
pluginVersion=2.1.0
pluginVersion=2.1.1
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
# for insight into build numbers and IntelliJ Platform versions.
pluginSinceBuild=222.3739.40
pluginSinceBuild=222.3739.54
pluginUntilBuild=222.*
# IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties
# Gateway available build versions https://www.jetbrains.com/intellij-repository/snapshots and https://www.jetbrains.com/intellij-repository/releases
platformType=GW
platformVersion=222.3739.40-CUSTOM-SNAPSHOT
instrumentationCompiler=222.3739.40-CUSTOM-SNAPSHOT
platformVersion=222.3739.54-CUSTOM-SNAPSHOT
instrumentationCompiler=222.3739.54-CUSTOM-SNAPSHOT
platformDownloadSources=true
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class CoderGatewayConnectionProvider : GatewayConnectionProvider {
}

val clientLifetime = LifetimeDefinition()
clientLifetime.launchUnderBackgroundProgress("Coder Gateway Deploy", canBeCancelled = true, isIndeterminate = true, project = null) {
clientLifetime.launchUnderBackgroundProgress(CoderGatewayBundle.message("gateway.connector.coder.connection.provider.title"), canBeCancelled = true, isIndeterminate = true, project = null) {
val context = SshMultistagePanelContext(
HostDeployInputs.FullySpecified(
remoteProjectPath = projectPath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import com.intellij.icons.AllIcons
import com.intellij.ide.ActivityTracker
import com.intellij.ide.BrowserUtil
import com.intellij.ide.IdeBundle
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
Expand Down Expand Up @@ -72,16 +73,23 @@ import java.awt.Dimension
import javax.swing.Icon
import javax.swing.JLabel
import javax.swing.JTable
import javax.swing.JTextField
import javax.swing.ListSelectionModel
import javax.swing.table.DefaultTableCellRenderer
import javax.swing.table.TableCellRenderer


private const val CODER_URL_KEY = "coder-url"

private const val SESSION_TOKEN = "session-token"

class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) : CoderWorkspacesWizardStep, Disposable {
private val cs = CoroutineScope(Dispatchers.Main)
private var localWizardModel = CoderWorkspacesWizardModel()
private val coderClient: CoderRestClientService = ApplicationManager.getApplication().getService(CoderRestClientService::class.java)
private val coderClient: CoderRestClientService = service()
private val appPropertiesService: PropertiesComponent = service()

private var tfUrl: JTextField? = null
private var listTableModelOfWorkspaces = ListTableModel<WorkspaceAgentModel>(
WorkspaceIconColumnInfo(""),
WorkspaceNameColumnInfo("Name"),
Expand Down Expand Up @@ -148,15 +156,15 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
browserLink(CoderGatewayBundle.message("gateway.connector.view.login.documentation.action"), "https://coder.com/docs/coder-oss/latest/workspaces")
}.bottomGap(BottomGap.MEDIUM)
row(CoderGatewayBundle.message("gateway.connector.view.login.url.label")) {
textField().resizableColumn().horizontalAlign(HorizontalAlign.FILL).gap(RightGap.SMALL).bindText(localWizardModel::coderURL).applyToComponent {
tfUrl = textField().resizableColumn().horizontalAlign(HorizontalAlign.FILL).gap(RightGap.SMALL).bindText(localWizardModel::coderURL).applyToComponent {
addActionListener {
poller?.cancel()
loginAndLoadWorkspace()
askTokenAndOpenSession()
}
}
}.component
button(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text")) {
poller?.cancel()
loginAndLoadWorkspace()
askTokenAndOpenSession()
}.applyToComponent {
background = WelcomeScreenUIManager.getMainAssociatedComponentBackground()
}
Expand Down Expand Up @@ -238,6 +246,17 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
enableNextButtonCallback(false)
if (localWizardModel.coderURL.isNotBlank() && localWizardModel.token.isNotBlank()) {
triggerWorkspacePolling()
} else {
val url = appPropertiesService.getValue(CODER_URL_KEY)
val token = appPropertiesService.getValue(SESSION_TOKEN)
if (!url.isNullOrBlank() && !token.isNullOrBlank()) {
localWizardModel.coderURL = url
localWizardModel.token = token
tfUrl?.text = url

poller?.cancel()
loginAndLoadWorkspace(token)
}
}
updateWorkspaceActions()
}
Expand Down Expand Up @@ -272,28 +291,31 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
ActivityTracker.getInstance().inc()
}

private fun loginAndLoadWorkspace() {
private fun askTokenAndOpenSession() {
// force bindings to be filled
component.apply()

BrowserUtil.browse(localWizardModel.coderURL.toURL().withPath("/login?redirect=%2Fcli-auth"))
val pastedToken = askToken()

if (pastedToken.isNullOrBlank()) {
return
}
loginAndLoadWorkspace(pastedToken)
}

private fun loginAndLoadWorkspace(token: String) {
try {
coderClient.initClientSession(localWizardModel.coderURL.toURL(), pastedToken)
coderClient.initClientSession(localWizardModel.coderURL.toURL(), token)
} catch (e: AuthenticationResponseException) {
logger.error("Could not authenticate on ${localWizardModel.coderURL}. Reason $e")
return
}

appPropertiesService.setValue(CODER_URL_KEY, localWizardModel.coderURL)
appPropertiesService.setValue(SESSION_TOKEN, token)
val cliManager = CoderCLIManager(localWizardModel.coderURL.toURL(), coderClient.buildVersion)


localWizardModel.apply {
token = pastedToken
this.token = token
buildVersion = coderClient.buildVersion
localCliPath = cliManager.localCliPath.toAbsolutePath().toString()
}
Expand Down Expand Up @@ -327,11 +349,14 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
}
}

ProgressManager.getInstance().run(authTask)
cs.launch {
ProgressManager.getInstance().run(authTask)
}
triggerWorkspacePolling()
}

private fun askToken(): String? {
BrowserUtil.browse(localWizardModel.coderURL.toURL().withPath("/login?redirect=%2Fcli-auth"))
return invokeAndWaitIfNeeded(ModalityState.any()) {
lateinit var sessionTokenTextField: JBTextField

Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/messages/CoderGatewayBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ gateway.connector.view.coder.remoteproject.choose.text=Choose IDE and project fo
gateway.connector.recentconnections.title=Recent Coder Workspaces
gateway.connector.recentconnections.new.wizard.button.tooltip=Open a new Coder Workspace
gateway.connector.recentconnections.remove.button.tooltip=Remove from Recent Connections
gateway.connector.recentconnections.terminal.button.tooltip=Open SSH Web Terminal
gateway.connector.recentconnections.terminal.button.tooltip=Open SSH Web Terminal
gateway.connector.coder.connection.provider.title=Connecting to Coder workspace...