diff --git a/CHANGELOG.md b/CHANGELOG.md index bdd6f03a..81252316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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] diff --git a/gradle.properties b/gradle.properties index 541b8aec..c5ff707f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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 diff --git a/src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt b/src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt index 6f82f39d..49100feb 100644 --- a/src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt +++ b/src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt @@ -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, diff --git a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt index dc270de6..dbd93cc6 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt @@ -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 @@ -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( WorkspaceIconColumnInfo(""), WorkspaceNameColumnInfo("Name"), @@ -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() } @@ -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() } @@ -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() } @@ -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 diff --git a/src/main/resources/messages/CoderGatewayBundle.properties b/src/main/resources/messages/CoderGatewayBundle.properties index 7ce0320a..5517b0e0 100644 --- a/src/main/resources/messages/CoderGatewayBundle.properties +++ b/src/main/resources/messages/CoderGatewayBundle.properties @@ -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 \ No newline at end of file +gateway.connector.recentconnections.terminal.button.tooltip=Open SSH Web Terminal +gateway.connector.coder.connection.provider.title=Connecting to Coder workspace... \ No newline at end of file