From 9e21ce9727c10bac6b8dbca42aa6c1a103588f44 Mon Sep 17 00:00:00 2001 From: Ioan Faur Date: Mon, 8 Aug 2022 23:28:09 +0300 Subject: [PATCH 1/6] Impl: merge auth step with workspaces step - simplifies the flows - allows users to quickly change the hostname - provides information about who provided the workspaces --- CHANGELOG.md | 40 +++--- .../views/CoderGatewayConnectorWizardView.kt | 2 - .../gateway/views/steps/CoderAuthStepView.kt | 6 +- .../views/steps/CoderWorkspacesStepView.kt | 126 +++++++++++++++++- .../messages/CoderGatewayBundle.properties | 8 +- 5 files changed, 150 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df5e35e0..e473bde7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,33 +1,39 @@ -# coder-gateway Changelog - -## [Unreleased] - -## [2.0.1] +# coder-gateway Changelog + +## [Unreleased] + +### Changed + +- the authentication view is now merged with the "Coder Workspaces" view allowing users to quickly change the host + +## [2.0.1] + ### Fixed + - `Recent Coder Workspaces` label overlaps with the search bar in the `Connections` view - working workspaces are now listed when there are issues with resolving agents - list only workspaces owned by the logged user - - + ### Changed + - links to documentation now point to the latest Coder OSS - simplified main action link text from `Connect to Coder Workspaces` to `Connect to Coder` -- minimum supported Gateway build is now 222.3739.24 - -## [2.0.0] -### Added +- minimum supported Gateway build is now 222.3739.24 + +## [2.0.0] +### Added - support for Gateway 2022.2 - -### Changed + +### Changed - Java 17 is now required to run the plugin -- adapted the code to the new SSH API provided by Gateway - -## [1.0.0] -### Added +- adapted the code to the new SSH API provided by Gateway + +## [1.0.0] +### Added - initial scaffold for Gateway plugin - browser based authentication on Coder environments - REST client for Coder V2 public API diff --git a/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardView.kt b/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardView.kt index a4dc130c..02252ba1 100644 --- a/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardView.kt +++ b/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardView.kt @@ -1,7 +1,6 @@ package com.coder.gateway.views import com.coder.gateway.models.CoderWorkspacesWizardModel -import com.coder.gateway.views.steps.CoderAuthStepView import com.coder.gateway.views.steps.CoderLocateRemoteProjectStepView import com.coder.gateway.views.steps.CoderWorkspacesStepView import com.coder.gateway.views.steps.CoderWorkspacesWizardStep @@ -29,7 +28,6 @@ class CoderGatewayConnectorWizardView(private val recentWorkspacesReset: () -> U private fun setupWizard() { background = WelcomeScreenUIManager.getMainAssociatedComponentBackground() - registerStep(CoderAuthStepView { next() }) registerStep(CoderWorkspacesStepView()) registerStep(CoderLocateRemoteProjectStepView { nextButton.isVisible = false diff --git a/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt b/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt index 0b45c0b5..a33b7745 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt @@ -54,7 +54,7 @@ class CoderAuthStepView(private val nextAction: () -> Unit) : CoderWorkspacesWiz } }.topGap(TopGap.SMALL).bottomGap(BottomGap.MEDIUM) row { - cell(ComponentPanelBuilder.createCommentComponent(CoderGatewayBundle.message("gateway.connector.view.login.comment.text"), false, -1, true)) + cell(ComponentPanelBuilder.createCommentComponent(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.comment"), false, -1, true)) } row { browserLink(CoderGatewayBundle.message("gateway.connector.view.login.documentation.action"), "https://coder.com/docs/coder-oss/latest/workspaces") @@ -72,7 +72,7 @@ class CoderAuthStepView(private val nextAction: () -> Unit) : CoderWorkspacesWiz background = WelcomeScreenUIManager.getMainAssociatedComponentBackground() } - override val nextActionText = CoderGatewayBundle.message("gateway.connector.view.coder.auth.next.text") + override val nextActionText = CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text") override val previousActionText = IdeBundle.message("button.back") override fun onInit(wizardModel: CoderWorkspacesWizardModel) { @@ -99,7 +99,7 @@ class CoderAuthStepView(private val nextAction: () -> Unit) : CoderWorkspacesWiz model.token = pastedToken model.buildVersion = coderClient.buildVersion - val authTask = object : Task.Modal(null, CoderGatewayBundle.message("gateway.connector.view.login.cli.downloader.dialog.title"), false) { + val authTask = object : Task.Modal(null, CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.cli.downloader.dialog.title"), false) { override fun run(pi: ProgressIndicator) { pi.apply { 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 7ddaec78..06b1f6b7 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt @@ -5,18 +5,35 @@ import com.coder.gateway.icons.CoderIcons import com.coder.gateway.models.CoderWorkspacesWizardModel import com.coder.gateway.models.WorkspaceAgentModel import com.coder.gateway.sdk.Arch +import com.coder.gateway.sdk.CoderCLIManager import com.coder.gateway.sdk.CoderRestClientService import com.coder.gateway.sdk.OS +import com.coder.gateway.sdk.ex.AuthenticationResponseException +import com.coder.gateway.sdk.getOS +import com.coder.gateway.sdk.toURL import com.coder.gateway.sdk.v2.models.ProvisionerJobStatus import com.coder.gateway.sdk.v2.models.Workspace import com.coder.gateway.sdk.v2.models.WorkspaceBuildTransition +import com.coder.gateway.sdk.withPath +import com.intellij.ide.BrowserUtil import com.intellij.ide.IdeBundle import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.application.invokeAndWaitIfNeeded import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.progress.Task +import com.intellij.openapi.ui.panel.ComponentPanelBuilder import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeScreenUIManager +import com.intellij.ui.AppIcon +import com.intellij.ui.components.JBTextField +import com.intellij.ui.components.dialog import com.intellij.ui.dsl.builder.BottomGap +import com.intellij.ui.dsl.builder.RightGap import com.intellij.ui.dsl.builder.TopGap +import com.intellij.ui.dsl.builder.bindText import com.intellij.ui.dsl.builder.panel import com.intellij.ui.dsl.gridLayout.HorizontalAlign import com.intellij.ui.dsl.gridLayout.VerticalAlign @@ -31,6 +48,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.zeroturnaround.exec.ProcessExecutor import java.awt.Color import java.awt.Component import java.awt.Dimension @@ -43,10 +61,9 @@ import javax.swing.table.TableCellRenderer class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { private val cs = CoroutineScope(Dispatchers.Main) - + private var wizardModel = CoderWorkspacesWizardModel() private val coderClient: CoderRestClientService = ApplicationManager.getApplication().getService(CoderRestClientService::class.java) - private var listTableModelOfWorkspaces = ListTableModel(WorkspaceIconColumnInfo(""), WorkspaceNameColumnInfo("Name"), WorkspaceTemplateNameColumnInfo("Template"), WorkspaceStatusColumnInfo("Status")) private var tableOfWorkspaces = TableView(listTableModelOfWorkspaces).apply { rowSelectionAllowed = true @@ -62,16 +79,31 @@ class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { setSelectionMode(ListSelectionModel.SINGLE_SELECTION) } - private lateinit var wizard: CoderWorkspacesWizardModel - override val component = panel { indent { row { - label(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.choose.text")).applyToComponent { + label(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.header.text")).applyToComponent { font = JBFont.h3().asBold() icon = CoderIcons.LOGO_16 } + }.topGap(TopGap.SMALL).bottomGap(BottomGap.MEDIUM) + row { + cell(ComponentPanelBuilder.createCommentComponent(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.comment"), false, -1, true)) + } + row { + 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(wizardModel::coderURL).applyToComponent { + addActionListener { + loginAndLoadWorkspace() + } + } + button(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text")) { + loginAndLoadWorkspace() + } + cell() + } row { scrollCell(tableOfWorkspaces).resizableColumn().horizontalAlign(HorizontalAlign.FILL).verticalAlign(VerticalAlign.FILL) cell() @@ -84,7 +116,89 @@ class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { override val nextActionText = CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.next.text") override fun onInit(wizardModel: CoderWorkspacesWizardModel) { - wizard = wizardModel + } + + private fun loginAndLoadWorkspace() { + // force bindings to be filled + component.apply() + + BrowserUtil.browse(wizardModel.coderURL.toURL().withPath("/login?redirect=%2Fcli-auth")) + val pastedToken = askToken() + + if (pastedToken.isNullOrBlank()) { + return + } + try { + coderClient.initClientSession(wizardModel.coderURL.toURL(), pastedToken) + } catch (e: AuthenticationResponseException) { + CoderAuthStepView.logger.error("Could not authenticate on ${wizardModel.coderURL}. Reason $e") + return + } + wizardModel.apply { + token = pastedToken + buildVersion = coderClient.buildVersion + } + + val authTask = object : Task.Modal(null, CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.cli.downloader.dialog.title"), false) { + override fun run(pi: ProgressIndicator) { + + pi.apply { + isIndeterminate = false + text = "Downloading coder cli..." + fraction = 0.1 + } + + val cliManager = CoderCLIManager(wizardModel.coderURL.toURL(), wizardModel.buildVersion) + val cli = cliManager.download() ?: throw IllegalStateException("Could not download coder binary") + if (getOS() != OS.WINDOWS) { + pi.fraction = 0.4 + val chmodOutput = ProcessExecutor().command("chmod", "+x", cli.toAbsolutePath().toString()).readOutput(true).execute().outputUTF8() + CoderAuthStepView.logger.info("chmod +x ${cli.toAbsolutePath()} $chmodOutput") + } + pi.apply { + text = "Configuring coder cli..." + fraction = 0.5 + } + + val loginOutput = ProcessExecutor().command(cli.toAbsolutePath().toString(), "login", wizardModel.coderURL, "--token", wizardModel.token).readOutput(true).execute().outputUTF8() + CoderAuthStepView.logger.info("coder-cli login output: $loginOutput") + pi.fraction = 0.8 + val sshConfigOutput = ProcessExecutor().command(cli.toAbsolutePath().toString(), "config-ssh", "--yes", "--use-previous-options").readOutput(true).execute().outputUTF8() + CoderAuthStepView.logger.info("Result of `${cli.toAbsolutePath()} config-ssh --yes --use-previous-options`: $sshConfigOutput") + pi.fraction = 1.0 + } + } + + wizardModel.apply { + coderURL = wizardModel.coderURL + token = wizardModel.token + } + ProgressManager.getInstance().run(authTask) + loadWorkspaces() + } + + private fun askToken(): String? { + return invokeAndWaitIfNeeded(ModalityState.any()) { + lateinit var sessionTokenTextField: JBTextField + + val panel = panel { + row { + label(CoderGatewayBundle.message("gateway.connector.view.login.token.label")) + sessionTokenTextField = textField().applyToComponent { + minimumSize = Dimension(320, -1) + }.component + } + } + + AppIcon.getInstance().requestAttention(null, true) + if (!dialog(CoderGatewayBundle.message("gateway.connector.view.login.token.dialog"), panel = panel, focusedComponent = sessionTokenTextField).showAndGet()) { + return@invokeAndWaitIfNeeded null + } + return@invokeAndWaitIfNeeded sessionTokenTextField.text + } + } + + private fun loadWorkspaces() { cs.launch { val workspaceList = withContext(Dispatchers.IO) { try { diff --git a/src/main/resources/messages/CoderGatewayBundle.properties b/src/main/resources/messages/CoderGatewayBundle.properties index 78b1ed11..35730af1 100644 --- a/src/main/resources/messages/CoderGatewayBundle.properties +++ b/src/main/resources/messages/CoderGatewayBundle.properties @@ -2,15 +2,15 @@ gateway.connector.title=Coder gateway.connector.description=Connects to a Coder Workspace dev environment so that you can develop from anywhere gateway.connector.action.text=Connect to Coder gateway.connector.view.login.header.text=Coder Workspaces -gateway.connector.view.login.comment.text=Self-hosted developer workspaces in the cloud or on premise. Coder Workspaces empower developers with secure, consistent, and fast developer workspaces. gateway.connector.view.login.documentation.action=Explore Coder Workspaces gateway.connector.view.login.url.label=Url: gateway.connector.view.login.token.dialog=Paste your token here: gateway.connector.view.login.token.label=Session Token: -gateway.connector.view.coder.auth.next.text=Connect -gateway.connector.view.login.cli.downloader.dialog.title=Authenticate and setup coder +gateway.connector.view.coder.workspaces.header.text=Coder Workspaces +gateway.connector.view.coder.workspaces.comment=Self-hosted developer workspaces in the cloud or on premise. Coder Workspaces empower developers with secure, consistent, and fast developer workspaces. +gateway.connector.view.coder.workspaces.connect.text=Connect +gateway.connector.view.coder.workspaces.cli.downloader.dialog.title=Authenticate and setup coder gateway.connector.view.coder.workspaces.next.text=Select IDE and Project -gateway.connector.view.coder.workspaces.choose.text=Choose a workspace gateway.connector.view.coder.remoteproject.loading.text=Retrieving products... gateway.connector.view.coder.remoteproject.ide.error.text=Could not retrieve any IDE for workspace {0} because an error was encountered gateway.connector.view.coder.remoteproject.next.text=Download and Start IDE From 0cc56c69ee5e9b10573f33f23c3b1a8cc464c220 Mon Sep 17 00:00:00 2001 From: Ioan Faur Date: Mon, 8 Aug 2022 23:29:36 +0300 Subject: [PATCH 2/6] Remove references to auth view --- .../coder/gateway/views/steps/CoderWorkspacesStepView.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 06b1f6b7..74b6f0a4 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt @@ -131,7 +131,7 @@ class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { try { coderClient.initClientSession(wizardModel.coderURL.toURL(), pastedToken) } catch (e: AuthenticationResponseException) { - CoderAuthStepView.logger.error("Could not authenticate on ${wizardModel.coderURL}. Reason $e") + logger.error("Could not authenticate on ${wizardModel.coderURL}. Reason $e") return } wizardModel.apply { @@ -153,7 +153,7 @@ class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { if (getOS() != OS.WINDOWS) { pi.fraction = 0.4 val chmodOutput = ProcessExecutor().command("chmod", "+x", cli.toAbsolutePath().toString()).readOutput(true).execute().outputUTF8() - CoderAuthStepView.logger.info("chmod +x ${cli.toAbsolutePath()} $chmodOutput") + logger.info("chmod +x ${cli.toAbsolutePath()} $chmodOutput") } pi.apply { text = "Configuring coder cli..." @@ -161,10 +161,10 @@ class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { } val loginOutput = ProcessExecutor().command(cli.toAbsolutePath().toString(), "login", wizardModel.coderURL, "--token", wizardModel.token).readOutput(true).execute().outputUTF8() - CoderAuthStepView.logger.info("coder-cli login output: $loginOutput") + logger.info("coder-cli login output: $loginOutput") pi.fraction = 0.8 val sshConfigOutput = ProcessExecutor().command(cli.toAbsolutePath().toString(), "config-ssh", "--yes", "--use-previous-options").readOutput(true).execute().outputUTF8() - CoderAuthStepView.logger.info("Result of `${cli.toAbsolutePath()} config-ssh --yes --use-previous-options`: $sshConfigOutput") + logger.info("Result of `${cli.toAbsolutePath()} config-ssh --yes --use-previous-options`: $sshConfigOutput") pi.fraction = 1.0 } } From 11cb4c9111a714d3f58389ce96de93b098813c19 Mon Sep 17 00:00:00 2001 From: Ioan Faur Date: Mon, 8 Aug 2022 23:30:03 +0300 Subject: [PATCH 3/6] Remove the auth view code --- .../gateway/views/steps/CoderAuthStepView.kt | 167 ------------------ 1 file changed, 167 deletions(-) delete mode 100644 src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt diff --git a/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt b/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt deleted file mode 100644 index a33b7745..00000000 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt +++ /dev/null @@ -1,167 +0,0 @@ -@file:Suppress("DialogTitleCapitalization") - -package com.coder.gateway.views.steps - -import com.coder.gateway.CoderGatewayBundle -import com.coder.gateway.icons.CoderIcons -import com.coder.gateway.models.CoderWorkspacesWizardModel -import com.coder.gateway.sdk.CoderCLIManager -import com.coder.gateway.sdk.CoderRestClientService -import com.coder.gateway.sdk.OS -import com.coder.gateway.sdk.ex.AuthenticationResponseException -import com.coder.gateway.sdk.getOS -import com.coder.gateway.sdk.toURL -import com.coder.gateway.sdk.withPath -import com.intellij.ide.BrowserUtil -import com.intellij.ide.IdeBundle -import com.intellij.openapi.Disposable -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.ModalityState -import com.intellij.openapi.application.invokeAndWaitIfNeeded -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.progress.ProgressManager -import com.intellij.openapi.progress.Task -import com.intellij.openapi.ui.panel.ComponentPanelBuilder -import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeScreenUIManager -import com.intellij.ui.AppIcon -import com.intellij.ui.components.JBTextField -import com.intellij.ui.components.dialog -import com.intellij.ui.dsl.builder.BottomGap -import com.intellij.ui.dsl.builder.RightGap -import com.intellij.ui.dsl.builder.TopGap -import com.intellij.ui.dsl.builder.bindText -import com.intellij.ui.dsl.builder.panel -import com.intellij.ui.dsl.gridLayout.HorizontalAlign -import com.intellij.util.ui.JBFont -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancel -import org.zeroturnaround.exec.ProcessExecutor -import java.awt.Dimension - -class CoderAuthStepView(private val nextAction: () -> Unit) : CoderWorkspacesWizardStep, Disposable { - private val cs = CoroutineScope(Dispatchers.Main) - private var model = CoderWorkspacesWizardModel() - private val coderClient: CoderRestClientService = ApplicationManager.getApplication().getService(CoderRestClientService::class.java) - - override val component = panel { - indent { - row { - label(CoderGatewayBundle.message("gateway.connector.view.login.header.text")).applyToComponent { - font = JBFont.h3().asBold() - icon = CoderIcons.LOGO_16 - } - }.topGap(TopGap.SMALL).bottomGap(BottomGap.MEDIUM) - row { - cell(ComponentPanelBuilder.createCommentComponent(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.comment"), false, -1, true)) - } - row { - 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(model::coderURL).applyToComponent { - addActionListener { - nextAction() - } - } - cell() - } - } - }.apply { - background = WelcomeScreenUIManager.getMainAssociatedComponentBackground() - } - - override val nextActionText = CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text") - override val previousActionText = IdeBundle.message("button.back") - - override fun onInit(wizardModel: CoderWorkspacesWizardModel) { - model.apply { - coderURL = wizardModel.coderURL - token = wizardModel.token - } - component.apply() - } - - override fun onNext(wizardModel: CoderWorkspacesWizardModel): Boolean { - BrowserUtil.browse(model.coderURL.toURL().withPath("/login?redirect=%2Fcli-auth")) - val pastedToken = askToken() - - if (pastedToken.isNullOrBlank()) { - return false - } - try { - coderClient.initClientSession(model.coderURL.toURL(), pastedToken) - } catch (e: AuthenticationResponseException) { - logger.error("Could not authenticate on ${model.coderURL}. Reason $e") - return false - } - model.token = pastedToken - model.buildVersion = coderClient.buildVersion - - val authTask = object : Task.Modal(null, CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.cli.downloader.dialog.title"), false) { - override fun run(pi: ProgressIndicator) { - - pi.apply { - isIndeterminate = false - text = "Downloading coder cli..." - fraction = 0.1 - } - - val cliManager = CoderCLIManager(model.coderURL.toURL(), model.buildVersion) - val cli = cliManager.download() ?: throw IllegalStateException("Could not download coder binary") - if (getOS() != OS.WINDOWS) { - pi.fraction = 0.4 - val chmodOutput = ProcessExecutor().command("chmod", "+x", cli.toAbsolutePath().toString()).readOutput(true).execute().outputUTF8() - logger.info("chmod +x ${cli.toAbsolutePath()} $chmodOutput") - } - pi.apply { - text = "Configuring coder cli..." - fraction = 0.5 - } - - val loginOutput = ProcessExecutor().command(cli.toAbsolutePath().toString(), "login", model.coderURL, "--token", model.token).readOutput(true).execute().outputUTF8() - logger.info("coder-cli login output: $loginOutput") - pi.fraction = 0.8 - val sshConfigOutput = ProcessExecutor().command(cli.toAbsolutePath().toString(), "config-ssh", "--yes", "--use-previous-options").readOutput(true).execute().outputUTF8() - logger.info("Result of `${cli.toAbsolutePath()} config-ssh --yes --use-previous-options`: $sshConfigOutput") - pi.fraction = 1.0 - } - } - wizardModel.apply { - coderURL = model.coderURL - token = model.token - } - ProgressManager.getInstance().run(authTask) - return true - } - - private fun askToken(): String? { - return invokeAndWaitIfNeeded(ModalityState.any()) { - lateinit var sessionTokenTextField: JBTextField - - val panel = panel { - row { - label(CoderGatewayBundle.message("gateway.connector.view.login.token.label")) - sessionTokenTextField = textField().applyToComponent { - minimumSize = Dimension(320, -1) - }.component - } - } - - AppIcon.getInstance().requestAttention(null, true) - if (!dialog(CoderGatewayBundle.message("gateway.connector.view.login.token.dialog"), panel = panel, focusedComponent = sessionTokenTextField).showAndGet()) { - return@invokeAndWaitIfNeeded null - } - return@invokeAndWaitIfNeeded sessionTokenTextField.text - } - } - - override fun dispose() { - cs.cancel() - } - - companion object { - val logger = Logger.getInstance(CoderAuthStepView::class.java.simpleName) - } -} \ No newline at end of file From a6441948640890cc5782e1affea535ea09f716f9 Mon Sep 17 00:00:00 2001 From: Ioan Faur Date: Mon, 8 Aug 2022 23:38:18 +0300 Subject: [PATCH 4/6] Fix button background --- .../com/coder/gateway/views/steps/CoderWorkspacesStepView.kt | 2 ++ 1 file changed, 2 insertions(+) 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 74b6f0a4..a0371ea6 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt @@ -101,6 +101,8 @@ class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { } button(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text")) { loginAndLoadWorkspace() + }.applyToComponent { + background = WelcomeScreenUIManager.getMainAssociatedComponentBackground() } cell() } From e0073957e8d1adef72cb3dfb26b0444125d1d0fa Mon Sep 17 00:00:00 2001 From: Ioan Faur Date: Tue, 9 Aug 2022 00:43:02 +0300 Subject: [PATCH 5/6] Fix: hide left panel when triggering new connections from Recent Workspaces --- CHANGELOG.md | 4 ++++ .../com/coder/gateway/CoderGatewayMainView.kt | 2 +- .../views/CoderGatewayConnectorWizardView.kt | 5 ++-- .../CoderGatewayConnectorWizardWrapperView.kt | 5 ++-- ...erGatewayRecentWorkspaceConnectionsView.kt | 23 ++++--------------- 5 files changed, 14 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e473bde7..9134585e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ # coder-gateway Changelog ## [Unreleased] +### Fixed + +- left panel is no longer visible when a new connection is triggered from Coder's "Recent Workspaces" panel. + This provides consistency with other plugins compatible with Gateway ### Changed diff --git a/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt b/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt index 9c4c7985..bb366459 100644 --- a/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt +++ b/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt @@ -36,7 +36,7 @@ class CoderGatewayMainView : GatewayConnector { } override fun getRecentConnections(setContentCallback: (Component) -> Unit): GatewayRecentConnections { - return CoderGatewayRecentWorkspaceConnectionsView() + return CoderGatewayRecentWorkspaceConnectionsView(setContentCallback) } override fun getTitle(): String { diff --git a/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardView.kt b/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardView.kt index 02252ba1..dd3d41e1 100644 --- a/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardView.kt +++ b/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardView.kt @@ -10,10 +10,11 @@ import com.intellij.ui.dsl.builder.RightGap import com.intellij.ui.dsl.builder.panel import com.intellij.ui.dsl.gridLayout.HorizontalAlign import com.intellij.util.ui.components.BorderLayoutPanel +import com.jetbrains.gateway.api.GatewayUI import java.awt.Component import javax.swing.JButton -class CoderGatewayConnectorWizardView(private val recentWorkspacesReset: () -> Unit) : BorderLayoutPanel(), Disposable { +class CoderGatewayConnectorWizardView : BorderLayoutPanel(), Disposable { private var steps = arrayListOf() private var currentStep = 0 private val model = CoderWorkspacesWizardModel() @@ -51,7 +52,7 @@ class CoderGatewayConnectorWizardView(private val recentWorkspacesReset: () -> U private fun previous() { if (currentStep == 0) { - recentWorkspacesReset() + GatewayUI.getInstance().reset() } else { remove(steps[currentStep].component) updateUI() diff --git a/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardWrapperView.kt b/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardWrapperView.kt index 8e25b44f..f48732ee 100644 --- a/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardWrapperView.kt +++ b/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectorWizardWrapperView.kt @@ -3,10 +3,9 @@ package com.coder.gateway.views import com.intellij.ui.components.panels.Wrapper import com.intellij.util.ui.JBUI import com.jetbrains.gateway.api.GatewayConnectorView -import com.jetbrains.gateway.api.GatewayUI import javax.swing.JComponent -class CoderGatewayConnectorWizardWrapperView(private val recentWorkspacesReset: () -> Unit = { GatewayUI.Companion.getInstance().reset() }) : GatewayConnectorView { +class CoderGatewayConnectorWizardWrapperView : GatewayConnectorView { override val component: JComponent - get() = Wrapper(CoderGatewayConnectorWizardView(recentWorkspacesReset)).apply { border = JBUI.Borders.empty() } + get() = Wrapper(CoderGatewayConnectorWizardView()).apply { border = JBUI.Borders.empty() } } \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt b/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt index ae99b38c..852133ef 100644 --- a/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt +++ b/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt @@ -13,7 +13,6 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.components.service import com.intellij.openapi.project.DumbAwareAction -import com.intellij.openapi.ui.DialogPanel import com.intellij.openapi.ui.panel.ComponentPanelBuilder import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeScreenUIManager import com.intellij.ui.DocumentAdapter @@ -28,7 +27,6 @@ import com.intellij.ui.dsl.gridLayout.HorizontalAlign import com.intellij.ui.dsl.gridLayout.VerticalAlign import com.intellij.util.ui.JBFont import com.intellij.util.ui.JBUI -import com.intellij.util.ui.components.BorderLayoutPanel import com.jetbrains.gateway.api.GatewayRecentConnections import com.jetbrains.gateway.api.GatewayUI import com.jetbrains.gateway.ssh.IntelliJPlatformProduct @@ -37,17 +35,16 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel import kotlinx.coroutines.launch +import java.awt.Component import java.awt.Dimension import javax.swing.JComponent import javax.swing.JLabel import javax.swing.event.DocumentEvent -class CoderGatewayRecentWorkspaceConnectionsView : GatewayRecentConnections, Disposable { +class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback: (Component) -> Unit) : GatewayRecentConnections, Disposable { private val recentConnectionsService = service() private val cs = CoroutineScope(Dispatchers.Main) - private val rootPanel = BorderLayoutPanel() - private lateinit var contentPanel: DialogPanel private val recentWorkspacesContentPanel = JBScrollPane() private lateinit var searchBar: SearchTextField @@ -57,7 +54,7 @@ class CoderGatewayRecentWorkspaceConnectionsView : GatewayRecentConnections, Dis override val recentsIcon = CoderIcons.LOGO_16 override fun createRecentsView(lifetime: Lifetime): JComponent { - contentPanel = panel { + return panel { indent { row { label(CoderGatewayBundle.message("gateway.connector.recentconnections.title")).applyToComponent { @@ -82,17 +79,7 @@ class CoderGatewayRecentWorkspaceConnectionsView : GatewayRecentConnections, Dis actionButton( object : DumbAwareAction(CoderGatewayBundle.message("gateway.connector.recentconnections.new.wizard.button.tooltip"), null, AllIcons.General.Add) { override fun actionPerformed(e: AnActionEvent) { - rootPanel.apply { - removeAll() - addToCenter(CoderGatewayConnectorWizardWrapperView { - rootPanel.apply { - removeAll() - addToCenter(contentPanel) - updateUI() - } - }.component) - updateUI() - } + setContentCallback(CoderGatewayConnectorWizardWrapperView().component) } }, ).gap(RightGap.SMALL) @@ -110,8 +97,6 @@ class CoderGatewayRecentWorkspaceConnectionsView : GatewayRecentConnections, Dis background = WelcomeScreenUIManager.getMainAssociatedComponentBackground() border = JBUI.Borders.empty(12, 0, 0, 12) } - - return rootPanel.addToCenter(contentPanel) } override fun getRecentsTitle() = CoderGatewayBundle.message("gateway.connector.title") From c449bb009c51ccd3a1cd22341d0647722402f704 Mon Sep 17 00:00:00 2001 From: Ioan Faur Date: Tue, 9 Aug 2022 00:46:17 +0300 Subject: [PATCH 6/6] Change label for next button in IDE&Project panel - for consistency with other plugin labels --- src/main/resources/messages/CoderGatewayBundle.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/resources/messages/CoderGatewayBundle.properties b/src/main/resources/messages/CoderGatewayBundle.properties index 35730af1..4fccebb1 100644 --- a/src/main/resources/messages/CoderGatewayBundle.properties +++ b/src/main/resources/messages/CoderGatewayBundle.properties @@ -1,7 +1,6 @@ gateway.connector.title=Coder gateway.connector.description=Connects to a Coder Workspace dev environment so that you can develop from anywhere gateway.connector.action.text=Connect to Coder -gateway.connector.view.login.header.text=Coder Workspaces gateway.connector.view.login.documentation.action=Explore Coder Workspaces gateway.connector.view.login.url.label=Url: gateway.connector.view.login.token.dialog=Paste your token here: @@ -13,7 +12,7 @@ gateway.connector.view.coder.workspaces.cli.downloader.dialog.title=Authenticate gateway.connector.view.coder.workspaces.next.text=Select IDE and Project gateway.connector.view.coder.remoteproject.loading.text=Retrieving products... gateway.connector.view.coder.remoteproject.ide.error.text=Could not retrieve any IDE for workspace {0} because an error was encountered -gateway.connector.view.coder.remoteproject.next.text=Download and Start IDE +gateway.connector.view.coder.remoteproject.next.text=Start IDE and Connect gateway.connector.view.coder.remoteproject.choose.text=Choose IDE and project for workspace {0} gateway.connector.recentconnections.title=Recent Coder Workspaces gateway.connector.recentconnections.new.wizard.button.tooltip=Open a new Coder Workspace