diff --git a/CHANGELOG.md b/CHANGELOG.md index b4b82464..f87d503b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,28 @@ -# coder-gateway Changelog - -## [Unreleased] - -## [2.0.0] +# coder-gateway Changelog + +## [Unreleased] +### 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` + +## [2.0.0] ### Added - support for Gateway 2022.2 - - + + ### 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/README.md b/README.md index 1415ddaa..dd0582bb 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=soc [![Coder Gateway Plugin Build](https://github.com/coder/coder-jetbrains/actions/workflows/build.yml/badge.svg)](https://github.com/coder/coder-jetbrains/actions/workflows/build.yml) -**Coder Gateway** connects your Jetbrains IDE to your [Coder Workspaces](https://coder.com/docs/coder/latest/workspaces) so that you can develop from anywhere. +**Coder Gateway** connects your Jetbrains IDE to your [Coder Workspaces](https://coder.com/docs/coder-oss/latest/workspaces) so that you can develop from anywhere. **Manage less** diff --git a/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt b/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt index 7c90cc4b..9c4c7985 100644 --- a/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt +++ b/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt @@ -32,7 +32,7 @@ class CoderGatewayMainView : GatewayConnector { } override fun getDocumentationLink(): ActionLink { - return BrowserLink("Learn more about Coder Workspaces", "https://coder.com/docs/coder/latest/workspaces") + return BrowserLink("Learn more", "https://coder.com/docs/coder-oss/latest") } override fun getRecentConnections(setContentCallback: (Component) -> Unit): GatewayRecentConnections { diff --git a/src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt b/src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt index 786a1512..0e37889c 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt @@ -80,7 +80,7 @@ class CoderRestClientService { * @throws WorkspaceResponseException if workspaces could not be retrieved. */ fun workspaces(): List { - val workspacesResponse = retroRestClient.workspaces().execute() + val workspacesResponse = retroRestClient.workspaces("owner:me").execute() if (!workspacesResponse.isSuccessful) { throw WorkspaceResponseException("Could not retrieve Coder Workspaces:${workspacesResponse.code()}, reason: ${workspacesResponse.message()}") } diff --git a/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt b/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt index 9ef91d52..0fcaa20e 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt @@ -7,6 +7,7 @@ import com.coder.gateway.sdk.v2.models.WorkspaceResource import retrofit2.Call import retrofit2.http.GET import retrofit2.http.Path +import retrofit2.http.Query import java.util.UUID interface CoderV2RestFacade { @@ -21,7 +22,7 @@ interface CoderV2RestFacade { * Retrieves all workspaces the authenticated user has access to. */ @GET("api/v2/workspaces") - fun workspaces(): Call> + fun workspaces(@Query("q") searchParams: String): Call> @GET("api/v2/buildinfo") fun buildInfo(): Call diff --git a/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt b/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt index 6c2f9e59..ae99b38c 100644 --- a/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt +++ b/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt @@ -39,6 +39,7 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import java.awt.Dimension import javax.swing.JComponent +import javax.swing.JLabel import javax.swing.event.DocumentEvent class CoderGatewayRecentWorkspaceConnectionsView : GatewayRecentConnections, Disposable { @@ -62,36 +63,42 @@ class CoderGatewayRecentWorkspaceConnectionsView : GatewayRecentConnections, Dis label(CoderGatewayBundle.message("gateway.connector.recentconnections.title")).applyToComponent { font = JBFont.h3().asBold() } - label("").resizableColumn().horizontalAlign(HorizontalAlign.FILL) - searchBar = cell(SearchTextField(false)).applyToComponent { - minimumSize = Dimension(350, -1) - textEditor.border = JBUI.Borders.empty(2, 5, 2, 0) - addDocumentListener(object : DocumentAdapter() { - override fun textChanged(e: DocumentEvent) { - val toSearchFor = this@applyToComponent.text - val filteredConnections = recentConnectionsService.getAllRecentConnections().filter { it.coderWorkspaceHostname?.toLowerCase()?.contains(toSearchFor) ?: false || it.projectPath?.toLowerCase()?.contains(toSearchFor) ?: false } - updateContentView(filteredConnections.groupBy { it.coderWorkspaceHostname }) - } - }) - }.component + panel { + indent { + row { + cell(JLabel()).resizableColumn().horizontalAlign(HorizontalAlign.FILL) + searchBar = cell(SearchTextField(false)).resizableColumn().horizontalAlign(HorizontalAlign.FILL).applyToComponent { + minimumSize = Dimension(350, -1) + textEditor.border = JBUI.Borders.empty(2, 5, 2, 0) + addDocumentListener(object : DocumentAdapter() { + override fun textChanged(e: DocumentEvent) { + val toSearchFor = this@applyToComponent.text + val filteredConnections = recentConnectionsService.getAllRecentConnections().filter { it.coderWorkspaceHostname?.toLowerCase()?.contains(toSearchFor) ?: false || it.projectPath?.toLowerCase()?.contains(toSearchFor) ?: false } + updateContentView(filteredConnections.groupBy { it.coderWorkspaceHostname }) + } + }) + }.component - 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() + 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() + } } - }.component) - updateUI() - } + }, + ).gap(RightGap.SMALL) } - }, - ).gap(RightGap.SMALL) + } + } }.bottomGap(BottomGap.MEDIUM) separator(background = WelcomeScreenUIManager.getSeparatorColor()) row { 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 012a8978..0b45c0b5 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt @@ -57,7 +57,7 @@ class CoderAuthStepView(private val nextAction: () -> Unit) : CoderWorkspacesWiz cell(ComponentPanelBuilder.createCommentComponent(CoderGatewayBundle.message("gateway.connector.view.login.comment.text"), false, -1, true)) } row { - browserLink(CoderGatewayBundle.message("gateway.connector.view.login.documentation.action"), "https://coder.com/docs/coder/latest/workspaces") + 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 { 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 f4fa0521..7ddaec78 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt @@ -8,6 +8,7 @@ import com.coder.gateway.sdk.Arch import com.coder.gateway.sdk.CoderRestClientService import com.coder.gateway.sdk.OS 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.intellij.ide.IdeBundle import com.intellij.openapi.Disposable @@ -87,23 +88,7 @@ class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { cs.launch { val workspaceList = withContext(Dispatchers.IO) { try { - val workspaces = coderClient.workspaces() - return@withContext workspaces.flatMap { workspace -> - val agents = coderClient.workspaceAgents(workspace) - val shouldContainAgentName = agents.size > 1 - agents.map { agent -> - val workspaceName = if (shouldContainAgentName) "${workspace.name}.${agent.name}" else workspace.name - WorkspaceAgentModel( - workspaceName, - workspace.templateName, - workspace.latestBuild.job.status, - workspace.latestBuild.workspaceTransition, - OS.from(agent.operatingSystem), - Arch.from(agent.architecture), - agent.directory - ) - } - } + return@withContext coderClient.workspaces().collectAgents() } catch (e: Exception) { logger.error("Could not retrieve workspaces for ${coderClient.me.username} on ${coderClient.coderURL}. Reason: $e") emptyList() @@ -115,6 +100,30 @@ class CoderWorkspacesStepView : CoderWorkspacesWizardStep, Disposable { } } + private fun List.collectAgents(): List { + return this.flatMap { workspace -> + try { + val agents = coderClient.workspaceAgents(workspace) + val shouldContainAgentName = agents.size > 1 + return@flatMap agents.map { agent -> + val workspaceName = if (shouldContainAgentName) "${workspace.name}.${agent.name}" else workspace.name + WorkspaceAgentModel( + workspaceName, + workspace.templateName, + workspace.latestBuild.job.status, + workspace.latestBuild.workspaceTransition, + OS.from(agent.operatingSystem), + Arch.from(agent.architecture), + agent.directory + ) + } + } catch (e: Exception) { + logger.error("Skipping workspace ${workspace.name} because we could not retrieve the agent(s). Reason: $e") + emptyList() + } + } + } + override fun onNext(wizardModel: CoderWorkspacesWizardModel): Boolean { val workspace = tableOfWorkspaces.selectedObject if (workspace != null) { diff --git a/src/main/resources/messages/CoderGatewayBundle.properties b/src/main/resources/messages/CoderGatewayBundle.properties index cff561cb..78b1ed11 100644 --- a/src/main/resources/messages/CoderGatewayBundle.properties +++ b/src/main/resources/messages/CoderGatewayBundle.properties @@ -1,6 +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 Workspaces +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