diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 71d08cbd4eb89b..855035e7967413 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -4,9 +4,6 @@
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 61445018c0889b..55f873a160926a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,9 +1,12 @@
+
+
+
-
+
diff --git a/components/ide/jetbrains/backend-plugin/gradle-latest.properties b/components/ide/jetbrains/backend-plugin/gradle-latest.properties
index 0777c7606a6cde..b024224ba1344f 100644
--- a/components/ide/jetbrains/backend-plugin/gradle-latest.properties
+++ b/components/ide/jetbrains/backend-plugin/gradle-latest.properties
@@ -6,4 +6,4 @@ pluginUntilBuild=242.*
# See https://jb.gg/intellij-platform-builds-list for available build versions.
pluginVerifierIdeVersions=2024.2
# Version from "com.jetbrains.intellij.idea" which can be found at https://www.jetbrains.com/intellij-repository/snapshots
-platformVersion=242.19533-EAP-CANDIDATE-SNAPSHOT
+platformVersion=242.20224-EAP-CANDIDATE-SNAPSHOT
diff --git a/components/ide/jetbrains/toolbox/build.gradle.kts b/components/ide/jetbrains/toolbox/build.gradle.kts
index ff6b421b5ec1e3..5d0329d66c87b0 100644
--- a/components/ide/jetbrains/toolbox/build.gradle.kts
+++ b/components/ide/jetbrains/toolbox/build.gradle.kts
@@ -1,3 +1,7 @@
+// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
+// Licensed under the GNU Affero General Public License (AGPL).
+// See License.AGPL.txt in the project root for license information.
+
import com.github.jk1.license.filter.ExcludeTransitiveDependenciesFilter
import com.github.jk1.license.render.JsonReportRenderer
import org.jetbrains.intellij.pluginRepository.PluginRepositoryFactory
@@ -34,12 +38,12 @@ dependencies {
implementation("com.connectrpc:connect-kotlin:0.6.0")
// Java specific dependencies.
implementation("com.connectrpc:connect-kotlin-google-java-ext:0.6.0")
- implementation("com.google.protobuf:protobuf-java:4.26.0")
+ implementation("com.google.protobuf:protobuf-java:4.27.2")
// WebSocket
compileOnly("javax.websocket:javax.websocket-api:1.1")
compileOnly("org.eclipse.jetty.websocket:websocket-api:9.4.54.v20240208")
implementation("org.eclipse.jetty.websocket:javax-websocket-client-impl:9.4.54.v20240208")
- // RD-Core
+ // RD-Core https://mvnrepository.com/artifact/com.jetbrains.rd/rd-core
implementation("com.jetbrains.rd:rd-core:2024.1.1")
implementation(libs.gateway.api)
diff --git a/components/ide/jetbrains/toolbox/gradle/libs.versions.toml b/components/ide/jetbrains/toolbox/gradle/libs.versions.toml
index cdac41588bd02c..be4d983bd2f69a 100644
--- a/components/ide/jetbrains/toolbox/gradle/libs.versions.toml
+++ b/components/ide/jetbrains/toolbox/gradle/libs.versions.toml
@@ -1,5 +1,5 @@
[versions]
-gateway = "2.4.0.30948"
+gateway = "2.4.0.31544"
kotlin = "1.9.0"
coroutines = "1.7.3"
serialization = "1.5.0"
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/auth/GitpodAuthManager.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/auth/GitpodAuthManager.kt
index d7148bd98a7f52..aea612ab5e8ef1 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/auth/GitpodAuthManager.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/auth/GitpodAuthManager.kt
@@ -60,19 +60,44 @@ class GitpodAuthManager {
manager.addEventListener {
when (it.type) {
AuthEvent.Type.LOGIN -> {
- logger.info("account ${it.accountId} logged in")
+ logger.debug("gitpod: user logged in ${it.accountId}")
+ resetCurrentAccount(it.accountId)
loginListeners.forEach { it() }
}
+
AuthEvent.Type.LOGOUT -> {
- logger.info("account ${it.accountId} logged out")
+ logger.debug("gitpod: user logged out ${it.accountId}")
+ resetCurrentAccount(it.accountId)
logoutListeners.forEach { it() }
}
}
}
}
+ private fun resetCurrentAccount(accountId: String) {
+ val account = manager.accountsWithStatus.find { it.account.id == accountId }?.account ?: return
+ logger.debug("reset settings for ${account.getHost()}")
+ Utils.gitpodSettings.resetSettings(account.getHost())
+ }
+
fun getCurrentAccount(): GitpodAccount? {
- return manager.accountsWithStatus.firstOrNull()?.account
+ return manager.accountsWithStatus.find { it.account.getHost() == Utils.gitpodSettings.gitpodHost }?.account
+ }
+
+ fun loginWithHost(host: String): Boolean {
+ if (getCurrentAccount()?.getHost() == host) {
+ // TODO: validate token is still available
+ return true
+ }
+ val account = manager.accountsWithStatus.find { it.account.getHost() == host }?.account
+ if (account != null) {
+ Utils.gitpodSettings.gitpodHost = host
+ loginListeners.forEach { it() }
+ // TODO: validate token is still available
+ return true
+ }
+ Utils.openUrl(this.getOAuthLoginUrl(host))
+ return false
}
fun logout() {
@@ -135,48 +160,12 @@ class GitpodAccount(
private val name: String,
private val host: String
) : Account {
- private val orgSelectedListeners: MutableList<(String) -> Unit> = mutableListOf()
- private val logger = LoggerFactory.getLogger(javaClass)
override fun getId() = id
override fun getFullName() = name
fun getCredentials() = credentials
fun getHost() = host
- private fun getStoreKey(key: String) = "USER:${id}:${key}"
-
- var organizationId: String?
- get() = Utils.settingStore[getStoreKey("ORG")]
- set(value){
- if (value == null) {
- return
- }
- Utils.settingStore[getStoreKey("ORG")] = value
- orgSelectedListeners.forEach { it(value) }
- }
-
- var preferEditor: String?
- get() = Utils.settingStore[getStoreKey("EDITOR")]
- set(value){
- if (value == null) {
- return
- }
- Utils.settingStore[getStoreKey("EDITOR")] = value
- }
-
- var preferWorkspaceClass: String?
- get() = Utils.settingStore[getStoreKey("WS_CLS")]
- set(value){
- if (value == null) {
- return
- }
- Utils.settingStore[getStoreKey("WS_CLS")] = value
- }
-
- fun onOrgSelected(listener: (String) -> Unit) {
- orgSelectedListeners.add(listener)
- }
-
fun encode(): String {
return Json.encodeToString(this)
}
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/auth/GitpodOrganizationPage.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/auth/GitpodOrganizationPage.kt
index 09f0cd8e6bc92e..5a9efbf80de4a0 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/auth/GitpodOrganizationPage.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/auth/GitpodOrganizationPage.kt
@@ -29,11 +29,11 @@ class GitpodOrganizationPage(val authManager: GitpodAuthManager, val publicApi:
val options = mutableListOf()
options.addAll(organizations.map { org ->
MenuItem(org.name, null, null) {
- authManager.getCurrentAccount()?.organizationId = org.id
+ Utils.gitpodSettings.organizationId = org.id
Utils.toolboxUi.hideUiPage(this)
}
})
- val orgName = organizations.find { it.id == authManager.getCurrentAccount()?.organizationId }?.name ?: ""
+ val orgName = organizations.find { it.id == Utils.gitpodSettings.organizationId }?.name ?: ""
AutocompleteTextField("Organization", orgName, options, 1.0f) {
if (it.isNullOrEmpty()) {
ValidationResult.Invalid("Organization is required")
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/colima/ColimaTestEnvironment.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/colima/ColimaTestEnvironment.kt
deleted file mode 100644
index e081717757af31..00000000000000
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/colima/ColimaTestEnvironment.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package io.gitpod.toolbox.colima
-
-import com.jetbrains.toolbox.gateway.AbstractRemoteProviderEnvironment
-import com.jetbrains.toolbox.gateway.EnvironmentVisibilityState
-import com.jetbrains.toolbox.gateway.environments.EnvironmentContentsView
-import com.jetbrains.toolbox.gateway.environments.ManualEnvironmentContentsView
-import com.jetbrains.toolbox.gateway.environments.SshEnvironmentContentsView
-import com.jetbrains.toolbox.gateway.ssh.SshConnectionInfo
-import com.jetbrains.toolbox.gateway.states.StandardRemoteEnvironmentState
-import com.jetbrains.toolbox.gateway.ui.ActionDescription
-import com.jetbrains.toolbox.gateway.ui.ActionListener
-import com.jetbrains.toolbox.gateway.ui.ObservableList
-import io.gitpod.toolbox.service.Utils
-import kotlinx.coroutines.launch
-import java.util.concurrent.CompletableFuture
-
-class ColimaTestEnvironment() : AbstractRemoteProviderEnvironment() {
- private val actionListeners = mutableSetOf()
- private val contentsViewFuture: CompletableFuture =
- CompletableFuture.completedFuture(ColimaSSHEnvironmentContentsView())
-
- init {
- Utils.coroutineScope.launch {
- Thread.sleep(2000)
- listenerSet.forEach { it.consume(StandardRemoteEnvironmentState.Active) }
- }
- }
-
- override fun getId(): String = "colima"
- override fun getName(): String = "colima"
-
- override fun getContentsView(): CompletableFuture = contentsViewFuture
-
- override fun setVisible(visibilityState: EnvironmentVisibilityState) {
-
- }
-
- override fun getActionList(): ObservableList {
- return Utils.observablePropertiesFactory.emptyObservableList()
- }
-
-}
-
-class ColimaSSHEnvironmentContentsView : SshEnvironmentContentsView, ManualEnvironmentContentsView {
- private val listenerSet = mutableSetOf()
-
- override fun getConnectionInfo(): CompletableFuture {
- return CompletableFuture.completedFuture(object : SshConnectionInfo {
- override fun getHost(): String = "127.0.0.1"
- override fun getPort() = 51710
- override fun getUserName() = "hwen"
- override fun getPrivateKeyPaths(): MutableList? {
- return mutableListOf("/Users/hwen/.colima/_lima/_config/user")
- }
- })
- }
-
- override fun addEnvironmentContentsListener(listener: ManualEnvironmentContentsView.Listener) {
- listenerSet += listener
- }
-
- override fun removeEnvironmentContentsListener(listener: ManualEnvironmentContentsView.Listener) {
- listenerSet -= listener
- }
-
-}
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodLogger.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodLogger.kt
index f9688e928bc094..f4cbda7f5fd0ab 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodLogger.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodLogger.kt
@@ -5,9 +5,9 @@
package io.gitpod.toolbox.gateway
import com.jetbrains.toolbox.gateway.deploy.DiagnosticInfoCollector
+import org.slf4j.Logger
import java.nio.file.Path
import java.util.concurrent.CompletableFuture
-import org.slf4j.Logger
class GitpodLogger(private val logger:Logger) : DiagnosticInfoCollector {
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodNewEnvironmentPage.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodNewEnvironmentPage.kt
deleted file mode 100644
index 4032bec4d9eaf9..00000000000000
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodNewEnvironmentPage.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package io.gitpod.toolbox.gateway
-
-import com.jetbrains.toolbox.gateway.ui.ActionDescription
-import com.jetbrains.toolbox.gateway.ui.ComboBoxField
-import com.jetbrains.toolbox.gateway.ui.TextField
-import com.jetbrains.toolbox.gateway.ui.TextType
-import com.jetbrains.toolbox.gateway.ui.UiField
-import io.gitpod.toolbox.auth.GitpodAuthManager
-import io.gitpod.toolbox.components.AbstractUiPage
-import io.gitpod.toolbox.components.SimpleButton
-import io.gitpod.toolbox.service.GitpodPublicApiManager
-import io.gitpod.toolbox.service.Utils
-import kotlinx.coroutines.launch
-import org.slf4j.LoggerFactory
-
-class GitpodNewEnvironmentPage(val authManager: GitpodAuthManager, val publicApi: GitpodPublicApiManager) :
- AbstractUiPage() {
- private val logger = LoggerFactory.getLogger(javaClass)
-
- override fun getFields(): MutableList {
- return mutableListOf(orgField, contextUrlField, editorField, workspaceClassField)
- }
-
- override fun getTitle(): String {
- return "New environment"
- }
-
- override fun getActionButtons(): MutableList {
- return mutableListOf(SimpleButton("Create") {
- val contextUrl = getFieldValue(contextUrlField) ?: return@SimpleButton
- val editor = getFieldValue(editorField) ?: return@SimpleButton
- val workspaceClass = getFieldValue(workspaceClassField) ?: return@SimpleButton
- if (contextUrl.isBlank()) {
- setActionErrorMessage("Context URL is required")
- return@SimpleButton
- }
- if (editor.isBlank()) {
- setActionErrorMessage("Editor is required")
- return@SimpleButton
- }
- if (workspaceClass.isBlank()) {
- setActionErrorMessage("Workspace class is required")
- return@SimpleButton
- }
- Utils.coroutineScope.launch {
- val workspace = publicApi.createAndStartWorkspace(contextUrl, editor, workspaceClass, null)
- logger.info("workspace: ${workspace.id} created")
- }
- })
- }
-
- private val orgField = getOrgField()
- private fun getOrgField(): TextField {
- // TODO: Use ComboBoxField or AutocompleteTextField with org results
- return TextField("Organization", authManager.getCurrentAccount()?.organizationId ?: "", TextType.General)
- }
-
- // TODO: Use AutocompleteTextField with suggestions from API
- // TODO: Add account recent repositories related field? Or get from auto start options
- private val contextUrlField =
- TextField("Context URL", "https://github.com/Gitpod-Samples/spring-petclinic", TextType.General)
-
- // TODO: get from API
- private val editorField = ComboBoxField(
- "Editor",
- authManager.getCurrentAccount()?.preferEditor ?: "intellij",
- listOf(
- ComboBoxField.LabelledValue("IntelliJ IDEA", "intellij"),
- ComboBoxField.LabelledValue("Goland", "goland")
- )
- )
-
- // TODO: get from API
- private val workspaceClassField = ComboBoxField(
- "Workspace Class",
- authManager.getCurrentAccount()?.preferWorkspaceClass ?: "g1-standard",
- listOf(ComboBoxField.LabelledValue("Standard", "g1-standard"), ComboBoxField.LabelledValue("Small", "g1-small"))
- )
-
- override fun fieldChanged(field: UiField) {
- super.fieldChanged(field)
- val account = authManager.getCurrentAccount() ?: return
- if (field == orgField) {
- val orgId = getFieldValue(orgField) ?: return
- logger.info("set prefer orgId: $orgId")
- account.organizationId = orgId
- // Not works
-// setFieldValue(orgField, orgId)
- return
- }
- if (field == editorField) {
- val editor = getFieldValue(editorField) ?: return
- logger.info("set prefer editor: $editor")
- account.preferEditor = editor
- return
- }
- if (field == workspaceClassField) {
- val cls = getFieldValue(workspaceClassField) ?: return
- logger.info("set prefer workspaceClass: $cls")
- account.preferWorkspaceClass = cls
- // Not works
-// setFieldValue(workspaceClassField, cls)
- return
- }
- }
-}
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodRemoteProvider.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodRemoteProvider.kt
index 23ef461c3e6056..fb0370f56cbc21 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodRemoteProvider.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodRemoteProvider.kt
@@ -14,15 +14,15 @@ import com.jetbrains.toolbox.gateway.ui.UiPage
import io.gitpod.toolbox.auth.GitpodAuthManager
import io.gitpod.toolbox.auth.GitpodLoginPage
import io.gitpod.toolbox.auth.GitpodOrganizationPage
-import io.gitpod.toolbox.colima.ColimaTestEnvironment
import io.gitpod.toolbox.components.GitpodIcon
import io.gitpod.toolbox.components.SimpleButton
+import io.gitpod.toolbox.service.ConnectParams
import io.gitpod.toolbox.service.GitpodPublicApiManager
import io.gitpod.toolbox.service.Utils
+import io.gitpod.toolbox.service.getConnectParams
import kotlinx.coroutines.launch
import org.slf4j.LoggerFactory
import java.net.URI
-import java.net.URLEncoder
class GitpodRemoteProvider(
private val consumer: RemoteEnvironmentConsumer,
@@ -31,69 +31,55 @@ class GitpodRemoteProvider(
private val authManger = GitpodAuthManager()
private val publicApi = GitpodPublicApiManager(authManger)
private val loginPage = GitpodLoginPage(authManger)
- private val newEnvPage = GitpodNewEnvironmentPage(authManger, publicApi)
private val organizationPage = GitpodOrganizationPage(authManger, publicApi)
// cache consumed environments map locally
private val environmentMap = mutableMapOf()
- private val openInToolboxUriHandler = GitpodOpenInToolboxUriHandler { connectParams ->
+ private var pendingConnectParams: Pair? = null
+ private val openInToolboxUriHandler = GitpodOpenInToolboxUriHandler { (gitpodHost, connectParams) ->
+ if (!authManger.loginWithHost(gitpodHost)) {
+ pendingConnectParams = gitpodHost to connectParams
+ return@GitpodOpenInToolboxUriHandler
+ }
+ Utils.toolboxUi.showWindow()
Utils.toolboxUi.showPluginEnvironmentsPage()
- setEnvironmentVisibility(connectParams.workspaceId)
+ setEnvironmentVisibility(connectParams)
}
// TODO: multiple host support
- private fun setEnvironmentVisibility(workspaceId: String) {
+ private fun setEnvironmentVisibility(connectParams: ConnectParams) {
+ val workspaceId = connectParams.workspaceId
logger.info("setEnvironmentVisibility $workspaceId")
- Utils.toolboxUi.showWindow()
- val env = environmentMap[workspaceId]
+ val env = environmentMap[connectParams.uniqueID]
if (env != null) {
env.markActive()
- Utils.clientHelper.setAutoConnectOnEnvironmentReady(workspaceId, "GO-233.15026.17", "/workspace/empty")
+ Utils.clientHelper.setAutoConnectOnEnvironmentReady(connectParams.uniqueID, "GO-242.20224.39", "/workspace/empty")
} else {
- GitpodRemoteProviderEnvironment(authManger, workspaceId, publicApi).apply {
- environmentMap[workspaceId] = this
+ GitpodRemoteProviderEnvironment(authManger, connectParams, publicApi).apply {
+ environmentMap[connectParams.uniqueID] = this
this.markActive()
consumer.consumeEnvironments(listOf(this))
- Utils.clientHelper.setAutoConnectOnEnvironmentReady(workspaceId, "GO-233.15026.17", "/workspace/empty")
+ Utils.clientHelper.setAutoConnectOnEnvironmentReady(workspaceId, "GO-242.20224.39", "/workspace/empty")
}
}
}
init {
- startup()
- authManger.addLoginListener {
- logger.info("user logged in ${authManger.getCurrentAccount()?.id}")
- startup()
- // TODO: showPluginEnvironmentsPage not refresh the page
- Utils.toolboxUi.showPluginEnvironmentsPage()
- }
- authManger.addLogoutListener {
- logger.info("user logged out ${authManger.getCurrentAccount()?.id}")
- // TODO: showPluginEnvironmentsPage not refresh the page
- Utils.toolboxUi.showPluginEnvironmentsPage()
- }
Utils.coroutineScope.launch {
Utils.dataManager.sharedWorkspaceList.collect { workspaces ->
if (workspaces.isEmpty()) {
return@collect
}
- workspaces.forEach{
- val host = URLEncoder.encode("https://exp-migration.preview.gitpod-dev.com", "UTF-8")
- val workspaceId = URLEncoder.encode(it.id, "UTF-8")
- val debugWorkspace = "false"
- val newUri = "jetbrains://gateway/io.gitpod.toolbox.gateway/open-in-toolbox?host=${host}&workspaceId=${workspaceId}&debugWorkspace=${debugWorkspace}"
- logger.info("workspace ${it.id} $newUri")
- }
consumer.consumeEnvironments(workspaces.map {
- val env = environmentMap[it.id]
- if (env != null) {
- env
- } else {
- val newEnv = GitpodRemoteProviderEnvironment(authManger, it.id, publicApi)
- environmentMap[it.id] = newEnv
- newEnv
+ val connectParams = it.getConnectParams()
+ val env = environmentMap[connectParams.uniqueID] ?: GitpodRemoteProviderEnvironment(authManger, connectParams, publicApi)
+ environmentMap[connectParams.uniqueID] = env
+ if (connectParams.uniqueID == pendingConnectParams?.second?.uniqueID) {
+ setEnvironmentVisibility(connectParams)
+ pendingConnectParams = null
}
+ env
})
}
}
@@ -102,7 +88,7 @@ class GitpodRemoteProvider(
private fun startup() {
val account = authManger.getCurrentAccount() ?: return
publicApi.setup()
- val orgId = account.organizationId
+ val orgId = Utils.gitpodSettings.organizationId
logger.info("user logged in, current selected org: $orgId")
if (orgId != null) {
Utils.dataManager.startWatchWorkspaces(publicApi)
@@ -112,14 +98,29 @@ class GitpodRemoteProvider(
Utils.toolboxUi.showUiPage(organizationPage)
}
}
- authManger.getCurrentAccount()?.onOrgSelected {
- Utils.dataManager.startWatchWorkspaces(publicApi)
+ Utils.gitpodSettings.onSettingsChanged { key, _ ->
+ when (key) {
+ GitpodSettings.SettingKey.ORGANIZATION_ID.name -> {
+ Utils.dataManager.startWatchWorkspaces(publicApi)
+ }
+ }
}
}
override fun getOverrideUiPage(): UiPage? {
- logger.info("getOverrideUiPage")
- authManger.getCurrentAccount() ?: return loginPage
+ val account = authManger.getCurrentAccount()
+ logger.info("get override ui page for ${account?.getHost()}")
+ account ?: return loginPage
+ startup()
+ authManger.addLoginListener {
+ Utils.toolboxUi.showWindow()
+ Utils.toolboxUi.showPluginEnvironmentsPage()
+ startup()
+ }
+ authManger.addLogoutListener {
+ Utils.toolboxUi.showWindow()
+ Utils.toolboxUi.showPluginEnvironmentsPage()
+ }
return null
}
@@ -128,7 +129,7 @@ class GitpodRemoteProvider(
override fun getName(): String = "Gitpod"
override fun getSvgIcon() = GitpodIcon()
- override fun getNewEnvironmentUiPage() = newEnvPage
+ override fun getNewEnvironmentUiPage() = UiPage.empty
override fun getAccountDropDown(): AccountDropdownField? {
val account = authManger.getCurrentAccount() ?: return null
@@ -137,28 +138,11 @@ class GitpodRemoteProvider(
}
}
- private fun testColima() = run {
- val env = ColimaTestEnvironment()
- consumer.consumeEnvironments(listOf(env))
- Utils.clientHelper.setAutoConnectOnEnvironmentReady("colima", "IU-241.14494.240", "/home/hwen.linux/project")
- }
-
override fun getAdditionalPluginActions(): MutableList {
return mutableListOf(
SimpleButton("View documents") {
Utils.openUrl("https://gitpod.io/docs")
},
- SimpleButton("Colima") {
- testColima()
- },
- SimpleButton("Show toast") {
- logger.info("toast shown")
- val t = Utils.toolboxUi.showInfoPopup("This is header", "This is content", "okText")
- Utils.coroutineScope.launch {
- t.get()
- logger.info("toast closed")
- }
- },
SimpleButton("Select organization") {
Utils.coroutineScope.launch {
organizationPage.loadData()
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodRemoteProviderEnvironment.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodRemoteProviderEnvironment.kt
index 4b1be52c5cb404..41686eec70c220 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodRemoteProviderEnvironment.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodRemoteProviderEnvironment.kt
@@ -7,6 +7,7 @@ package io.gitpod.toolbox.gateway
import com.jetbrains.toolbox.gateway.AbstractRemoteProviderEnvironment
import com.jetbrains.toolbox.gateway.EnvironmentVisibilityState
import com.jetbrains.toolbox.gateway.environments.EnvironmentContentsView
+import com.jetbrains.toolbox.gateway.states.EnvironmentStateConsumer
import com.jetbrains.toolbox.gateway.states.StandardRemoteEnvironmentState
import com.jetbrains.toolbox.gateway.ui.ActionDescription
import com.jetbrains.toolbox.gateway.ui.ObservableList
@@ -14,6 +15,7 @@ import io.gitpod.publicapi.v1.WorkspaceOuterClass
import io.gitpod.publicapi.v1.WorkspaceOuterClass.WorkspacePhase
import io.gitpod.toolbox.auth.GitpodAuthManager
import io.gitpod.toolbox.components.SimpleButton
+import io.gitpod.toolbox.service.ConnectParams
import io.gitpod.toolbox.service.GitpodPublicApiManager
import io.gitpod.toolbox.service.Utils
import kotlinx.coroutines.channels.BufferOverflow
@@ -24,7 +26,7 @@ import java.util.concurrent.CompletableFuture
class GitpodRemoteProviderEnvironment(
private val authManager: GitpodAuthManager,
- private val workspaceId: String,
+ private val connectParams: ConnectParams,
private val publicApi: GitpodPublicApiManager,
) : AbstractRemoteProviderEnvironment() {
private val logger = LoggerFactory.getLogger(javaClass)
@@ -32,7 +34,7 @@ class GitpodRemoteProviderEnvironment(
private val contentsViewFuture: CompletableFuture = CompletableFuture.completedFuture(
GitpodSSHEnvironmentContentsView(
authManager,
- workspaceId,
+ connectParams,
publicApi,
)
)
@@ -40,7 +42,7 @@ class GitpodRemoteProviderEnvironment(
private val lastWSEnvState = MutableSharedFlow(1, 0, BufferOverflow.DROP_OLDEST)
private var lastPhase: WorkspacePhase =
WorkspacePhase.newBuilder().setNameValue(WorkspacePhase.Phase.PHASE_UNSPECIFIED_VALUE).build()
- private var isMarkActive = false
+ public var isMarkActive = false
set(value) {
if (field != value) {
field = value
@@ -53,14 +55,6 @@ class GitpodRemoteProviderEnvironment(
}
init {
- logger.info("==================GitpodRemoteProviderEnvironment.init $workspaceId")
- Utils.coroutineScope.launch {
- Utils.dataManager.watchWorkspaceStatus(workspaceId) {
- lastPhase = it.phase
- lastWSEnvState.tryEmit(WorkspaceEnvState(it.phase, isMarkActive))
- }
- }
-
Utils.coroutineScope.launch {
lastWSEnvState.collect { lastState ->
val state = lastState.getState()
@@ -76,20 +70,30 @@ class GitpodRemoteProviderEnvironment(
Utils.coroutineScope.launch { contentsViewFuture.get().close() }
}
}
- if (lastState.isStoppable) {
- actions += SimpleButton("Stop workspace") {
- logger.info("===============stop workspace clicked")
- }
- }
actionList.clear()
actionList.addAll(actions)
listenerSet.forEach { it.consume(state) }
}
}
+
+ Utils.coroutineScope.launch {
+ Utils.dataManager.watchWorkspaceStatus(connectParams.workspaceId) {
+ lastPhase = it.phase
+ lastWSEnvState.tryEmit(WorkspaceEnvState(it.phase, isMarkActive))
+ }
+ }
+ }
+
+ override fun addStateListener(consumer: EnvironmentStateConsumer): Boolean {
+ val ok = super.addStateListener(consumer)
+ Utils.coroutineScope.launch {
+ lastWSEnvState.tryEmit(WorkspaceEnvState(lastPhase, isMarkActive))
+ }
+ return ok
}
- override fun getId(): String = workspaceId
- override fun getName(): String = workspaceId
+ override fun getId(): String = connectParams.uniqueID
+ override fun getName(): String = connectParams.resolvedWorkspaceId
override fun getContentsView(): CompletableFuture = contentsViewFuture
@@ -104,7 +108,6 @@ class GitpodRemoteProviderEnvironment(
private class WorkspaceEnvState(val phase: WorkspacePhase, val isMarkActive: Boolean) {
val isConnectable = phase.nameValue == WorkspaceOuterClass.WorkspacePhase.Phase.PHASE_RUNNING_VALUE && !isMarkActive
val isCloseable = isMarkActive
- val isStoppable = phase.nameValue == WorkspaceOuterClass.WorkspacePhase.Phase.PHASE_RUNNING_VALUE
fun getState() = run {
if (isMarkActive && phase.nameValue == WorkspaceOuterClass.WorkspacePhase.Phase.PHASE_RUNNING_VALUE) {
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodSSHEnvironmentContentsView.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodSSHEnvironmentContentsView.kt
index daa087ce41a485..2deeecb09893ab 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodSSHEnvironmentContentsView.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodSSHEnvironmentContentsView.kt
@@ -8,6 +8,7 @@ import com.jetbrains.toolbox.gateway.environments.ManualEnvironmentContentsView
import com.jetbrains.toolbox.gateway.environments.SshEnvironmentContentsView
import com.jetbrains.toolbox.gateway.ssh.SshConnectionInfo
import io.gitpod.toolbox.auth.GitpodAuthManager
+import io.gitpod.toolbox.service.ConnectParams
import io.gitpod.toolbox.service.GitpodConnectionProvider
import io.gitpod.toolbox.service.GitpodPublicApiManager
import io.gitpod.toolbox.service.Utils
@@ -17,7 +18,7 @@ import java.util.concurrent.CompletableFuture
class GitpodSSHEnvironmentContentsView(
private val authManager: GitpodAuthManager,
- private val workspaceId: String,
+ private val connectParams: ConnectParams,
private val publicApi: GitpodPublicApiManager,
) : SshEnvironmentContentsView, ManualEnvironmentContentsView {
private var cancel = {}
@@ -27,7 +28,7 @@ class GitpodSSHEnvironmentContentsView(
override fun getConnectionInfo(): CompletableFuture {
return Utils.coroutineScope.future {
- val provider = GitpodConnectionProvider(authManager, workspaceId, publicApi)
+ val provider = GitpodConnectionProvider(authManager, connectParams, publicApi)
val (connInfo, cancel) = provider.connect()
this@GitpodSSHEnvironmentContentsView.cancel = cancel
return@future connInfo
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodSettings.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodSettings.kt
new file mode 100644
index 00000000000000..b3d12f3ae764e5
--- /dev/null
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodSettings.kt
@@ -0,0 +1,51 @@
+// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
+// Licensed under the GNU Affero General Public License (AGPL).
+// See License.AGPL.txt in the project root for license information.
+
+package io.gitpod.toolbox.gateway
+
+import io.gitpod.toolbox.service.Utils
+import org.slf4j.LoggerFactory
+
+class GitpodSettings {
+ private val logger = LoggerFactory.getLogger(javaClass)
+ private val settingsChangedListeners: MutableList<(String, String) -> Unit> = mutableListOf()
+
+ private fun getStoreKey(key: SettingKey) = "GITPOD_SETTINGS:${key.name}"
+
+ private fun updateSetting(key: SettingKey, value: String) {
+ logger.debug("updateSetting ${key.name}=$value")
+ Utils.settingStore[getStoreKey(key)] = value
+ settingsChangedListeners.forEach { it(key.name, value) }
+ }
+
+ fun onSettingsChanged(listener: (String, String) -> Unit) {
+ settingsChangedListeners.add(listener)
+ }
+
+ var organizationId: String?
+ get() {
+ val value = Utils.settingStore[getStoreKey(SettingKey.ORGANIZATION_ID)]
+ return if (value.isNullOrBlank()) null else value
+ }
+ set(value) {
+ updateSetting(SettingKey.ORGANIZATION_ID, value ?: "")
+ }
+
+ fun resetSettings(host: String = "gitpod.io") {
+ logger.info("=============reset for $host")
+ gitpodHost = host
+ organizationId = ""
+ }
+
+ var gitpodHost: String
+ get() = Utils.settingStore[getStoreKey(SettingKey.GITPOD_HOST)] ?: "gitpod.io"
+ set(value) {
+ updateSetting(SettingKey.GITPOD_HOST, value)
+ }
+
+ enum class SettingKey {
+ ORGANIZATION_ID,
+ GITPOD_HOST
+ }
+}
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodUriHandler.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodUriHandler.kt
index 74b7dd4e2f0c0b..04b0dee7cce510 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodUriHandler.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/GitpodUriHandler.kt
@@ -31,10 +31,13 @@ abstract class AbstractUriHandler : UriHandler {
}
}
-class GitpodOpenInToolboxUriHandler(val handler: (ConnectParams) -> Unit) : AbstractUriHandler() {
- override fun handle(data: ConnectParams): Future = CompletableFuture.runAsync { handler(data) }
+class GitpodOpenInToolboxUriHandler(val handler: (Pair) -> Unit) : AbstractUriHandler>() {
- override fun parseUri(uri: URI): ConnectParams {
+ private val logger = LoggerFactory.getLogger(javaClass)
+
+ override fun handle(data: Pair): Future = CompletableFuture.runAsync { handler(data) }
+
+ override fun parseUri(uri: URI): Pair {
val path = uri.path.split("/").last()
if (path != "open-in-toolbox") {
throw IllegalArgumentException("invalid URI: $path")
@@ -54,7 +57,7 @@ class GitpodOpenInToolboxUriHandler(val handler: (ConnectParams) -> Unit) : Abst
} catch (e: IllegalArgumentException) {
throw IllegalArgumentException("invalid host: $host")
}
-
- return ConnectParams(host, workspaceId, debugWorkspace)
+ logger.info("gitpod: parsed URI: $host, $workspaceId, $debugWorkspace")
+ return Pair("https://$host", ConnectParams(workspaceId, debugWorkspace))
}
}
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/DataManager.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/DataManager.kt
index 7e4feb841e6463..df947e6761cf00 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/DataManager.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/DataManager.kt
@@ -83,3 +83,7 @@ class DataManager {
}
}
}
+
+fun WorkspaceOuterClass.Workspace.getConnectParams(): ConnectParams {
+ return ConnectParams(id, false)
+}
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/GitpodConnectionProvider.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/GitpodConnectionProvider.kt
index ea981091b8920f..e7669f10decb3a 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/GitpodConnectionProvider.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/GitpodConnectionProvider.kt
@@ -10,21 +10,24 @@ import com.jetbrains.toolbox.gateway.ssh.SshConnectionInfo
import io.gitpod.publicapi.v1.WorkspaceOuterClass
import io.gitpod.toolbox.auth.GitpodAuthManager
import kotlinx.serialization.Serializable
+import org.slf4j.LoggerFactory
class GitpodConnectionProvider(
private val authManager: GitpodAuthManager,
- private val workspaceId: String,
+ private val connectParams: ConnectParams,
private val publicApi: GitpodPublicApiManager,
) {
+ private val logger = LoggerFactory.getLogger(javaClass)
private val activeConnections = ConcurrentHashMap()
suspend fun connect(): Pair Unit> {
+ val workspaceId = connectParams.workspaceId
val workspace = publicApi.getWorkspace(workspaceId).workspace
val ownerTokenResp = publicApi.getWorkspaceOwnerToken(workspaceId)
val account = authManager.getCurrentAccount() ?: throw Exception("No account found")
// TODO: debug workspace
- val connectParams = ConnectParams(account.getHost(), workspaceId, false)
+ val connectParams = ConnectParams(workspaceId, false)
val (serverPort, cancel) = tunnelWithWebSocket(workspace, connectParams, ownerTokenResp.ownerToken)
@@ -80,13 +83,12 @@ class GitpodWebSocketSshConnectionInfo(
}
data class ConnectParams(
- val gitpodHost: String,
val workspaceId: String,
val debugWorkspace: Boolean = false,
) {
val resolvedWorkspaceId = "${if (debugWorkspace) "debug-" else ""}$workspaceId"
- val title = "$resolvedWorkspaceId ($gitpodHost)"
- val uniqueID = "$gitpodHost-$workspaceId-$debugWorkspace"
+ val title = "$resolvedWorkspaceId"
+ val uniqueID = "$workspaceId-$debugWorkspace"
}
@Serializable
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/GitpodPublicApiManager.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/GitpodPublicApiManager.kt
index 504878a358d4cc..a4c34389e33ea6 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/GitpodPublicApiManager.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/GitpodPublicApiManager.kt
@@ -50,7 +50,7 @@ class GitpodPublicApiManager(private val authManger: GitpodAuthManager) {
}
private val orgId: String
- get() = account?.organizationId ?: throw IllegalStateException("Organization not selected")
+ get() = Utils.gitpodSettings.organizationId ?: throw IllegalStateException("Organization not selected")
suspend fun listOrganizations(): List {
val organizationApi = organizationApi ?: throw IllegalStateException("No client")
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/PageRouter.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/PageRouter.kt
deleted file mode 100644
index d82cb5b0583ede..00000000000000
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/PageRouter.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2024 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package io.gitpod.toolbox.service
-
-import com.jetbrains.toolbox.gateway.ui.LabelField
-import com.jetbrains.toolbox.gateway.ui.UiField
-import com.jetbrains.toolbox.gateway.ui.UiPage
-import org.slf4j.LoggerFactory
-
-interface Route {
- val path: String
- val page: UiPage
-}
-
-class PageRouter {
- private val logger = LoggerFactory.getLogger(javaClass)
- private val history = mutableListOf()
- private val routes: MutableList = mutableListOf()
- private val listeners: MutableList<(String?) -> Unit> = mutableListOf()
-
- fun addRoutes(vararg newRoutes: Route) {
- logger.info("add routes: {}", newRoutes.map { it.path })
- this.routes.addAll(newRoutes)
- }
-
- fun goTo(path: String) {
- val route = routes.find { it.path == path } ?: kotlin.run {
- logger.warn("route not found: $path")
- return
- }
- logger.info("go to route: ${route.path}")
- history.add(route)
- notifyListeners()
- }
-
- fun goBack() {
- logger.info("go back")
- if (history.size >= 1) {
- history.removeAt(history.size - 1)
- notifyListeners()
- } else {
- logger.warn("no route to go back")
- return
- }
- }
-
- fun getCurrentPage(): Pair {
- logger.info("current page: ${history.lastOrNull()?.page}")
- val route = history.lastOrNull() ?: return PageNotFound() to true
- return route.page to false
- }
-
- fun addListener(listener: (String?) -> Unit): () -> Unit {
- listeners.add(listener)
- return {
- listeners.remove(listener)
- }
- }
-
- private fun notifyListeners() {
- listeners.forEach { it(history.lastOrNull()?.path) }
- }
-}
-
-class PageNotFound : UiPage {
- override fun getTitle(): String {
- return "Not Found"
- }
-
- override fun getFields(): MutableList {
- return mutableListOf(LabelField("Not found"))
- }
-}
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/Utils.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/Utils.kt
index 05b785e6400084..067f8ce6b759c0 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/Utils.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/service/Utils.kt
@@ -11,6 +11,7 @@ import com.jetbrains.toolbox.gateway.connection.ToolboxProxySettings
import com.jetbrains.toolbox.gateway.ssh.validation.SshConnectionValidator
import com.jetbrains.toolbox.gateway.ui.ObservablePropertiesFactory
import com.jetbrains.toolbox.gateway.ui.ToolboxUi
+import io.gitpod.toolbox.gateway.GitpodSettings
import kotlinx.coroutines.CoroutineScope
import okhttp3.OkHttpClient
import java.net.Proxy
@@ -26,6 +27,7 @@ object Utils {
lateinit var observablePropertiesFactory: ObservablePropertiesFactory private set
lateinit var proxySettings: ToolboxProxySettings private set
+ lateinit var gitpodSettings: GitpodSettings private set
lateinit var dataManager: DataManager private set
lateinit var toolboxUi: ToolboxUi private set
@@ -45,6 +47,7 @@ object Utils {
observablePropertiesFactory = serviceLocator.getService(ObservablePropertiesFactory::class.java)
proxySettings = serviceLocator.getService(ToolboxProxySettings::class.java)
dataManager = DataManager()
+ gitpodSettings = GitpodSettings()
}
fun openUrl(url: String) {
diff --git a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/await.kt b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/utils/await.kt
similarity index 96%
rename from components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/await.kt
rename to components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/utils/await.kt
index 12e1be26d3b2fd..4be6a3a1583812 100644
--- a/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/gateway/await.kt
+++ b/components/ide/jetbrains/toolbox/src/main/kotlin/io/gitpod/toolbox/utils/await.kt
@@ -2,7 +2,7 @@
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.
-package io.gitpod.toolbox.gateway
+package io.gitpod.toolbox.utils
import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.Call