diff --git a/lib/webrtc-java-0.6.0-windows-x86_64.jar b/lib/webrtc-java-0.6.0-windows-x86_64.jar deleted file mode 100644 index 4c98c161..00000000 Binary files a/lib/webrtc-java-0.6.0-windows-x86_64.jar and /dev/null differ diff --git a/lib/webrtc-java-0.6.0.jar b/lib/webrtc-java-0.6.0.jar deleted file mode 100644 index eead2075..00000000 Binary files a/lib/webrtc-java-0.6.0.jar and /dev/null differ diff --git a/src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt b/src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt index 7463c5b6..9214529f 100644 --- a/src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt +++ b/src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt @@ -1,3 +1,5 @@ +@file:Suppress("DialogTitleCapitalization") + package com.coder.gateway import com.coder.gateway.models.RecentWorkspaceConnection @@ -63,7 +65,7 @@ class CoderGatewayConnectionProvider : GatewayConnectionProvider { buildNumber = ideBuildNumber ) - clientLifetime.launchUnderBackgroundProgress("Coder Gateway Deploy", true, true, null) { + clientLifetime.launchUnderBackgroundProgress("Coder Gateway Deploy", canBeCancelled = true, isIndeterminate = true, project = null) { val context = SshMultistagePanelContext().apply { deploy = true sshConfig = sshConfiguration @@ -74,6 +76,7 @@ class CoderGatewayConnectionProvider : GatewayConnectionProvider { ide = ideConfig } launch { + @Suppress("UnstableApiUsage") SshDeployFlowUtil.fullDeployCycle( clientLifetime, context, diff --git a/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt b/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt index f0d788bd..5b9f0395 100644 --- a/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt +++ b/src/main/kotlin/com/coder/gateway/CoderGatewayMainView.kt @@ -25,15 +25,15 @@ class CoderGatewayMainView : GatewayConnector { return CoderGatewayBundle.message("gateway.connector.action.text") } - override fun getDescription(): String? { + override fun getDescription(): String { return CoderGatewayBundle.message("gateway.connector.description") } - override fun getDocumentationLink(): ActionLink? { + override fun getDocumentationLink(): ActionLink { return BrowserLink(null, "Learn more about Coder Workspaces", null, "https://coder.com/docs/coder/latest/workspaces") } - override fun getRecentConnections(setContentCallback: (Component) -> Unit): GatewayRecentConnections? { + override fun getRecentConnections(setContentCallback: (Component) -> Unit): GatewayRecentConnections { return CoderGatewayRecentWorkspaceConnectionsView() } diff --git a/src/main/kotlin/com/coder/gateway/sdk/CoderCLIDownloader.kt b/src/main/kotlin/com/coder/gateway/sdk/CoderCLIDownloader.kt index 251cbbe1..5f17e7ae 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/CoderCLIDownloader.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/CoderCLIDownloader.kt @@ -11,7 +11,7 @@ import java.nio.file.StandardCopyOption class CoderCLIDownloader(private val buildVersion: String) { fun downloadCLI(url: URL, outputName: String, ext: String): Path { - val filename = if (ext.isNullOrBlank()) "${outputName}-$buildVersion" else "${outputName}-${buildVersion}.${ext}" + val filename = if (ext.isBlank()) "${outputName}-$buildVersion" else "${outputName}-${buildVersion}.${ext}" val cliPath = Paths.get(System.getProperty("java.io.tmpdir"), filename) if (Files.exists(cliPath)) { logger.info("${cliPath.toAbsolutePath()} already exists, skipping download") diff --git a/src/main/kotlin/com/coder/gateway/sdk/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/sdk/CoderCLIManager.kt index e05d6664..85a0b52f 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/CoderCLIManager.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/CoderCLIManager.kt @@ -4,7 +4,7 @@ import com.intellij.openapi.diagnostic.Logger import java.net.URL import java.nio.file.Path -class CoderCLIManager(private val url: URL, private val buildVersion: String) { +class CoderCLIManager(private val url: URL, buildVersion: String) { private val coderCLIDownloader = CoderCLIDownloader(buildVersion) fun download(): Path? { @@ -21,19 +21,19 @@ class CoderCLIManager(private val url: URL, private val buildVersion: String) { } return when (os) { OS.WINDOWS -> when (arch) { - Arch.amd64 -> "coder-windows-amd64" - Arch.arm64 -> "coder-windows-arm64" + Arch.AMD64 -> "coder-windows-amd64" + Arch.ARM64 -> "coder-windows-arm64" else -> "coder-windows-amd64" } OS.LINUX -> when (arch) { - Arch.amd64 -> "coder-linux-amd64" - Arch.arm64 -> "coder-linux-arm64" - Arch.armv7 -> "coder-linux-armv7" + Arch.AMD64 -> "coder-linux-amd64" + Arch.ARM64 -> "coder-linux-arm64" + Arch.ARMV7 -> "coder-linux-armv7" else -> "coder-linux-amd64" } OS.MAC -> when (arch) { - Arch.amd64 -> "coder-darwin-amd64" - Arch.arm64 -> "coder-darwin-arm64" + Arch.AMD64 -> "coder-darwin-amd64" + Arch.ARM64 -> "coder-darwin-arm64" else -> "coder-darwin-amd64" } } diff --git a/src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt b/src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt index b8b80b1e..f7723d86 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt @@ -3,7 +3,6 @@ package com.coder.gateway.sdk import com.coder.gateway.sdk.convertors.InstantConverter import com.coder.gateway.sdk.ex.AuthenticationException import com.coder.gateway.sdk.v2.CoderV2RestFacade -import com.coder.gateway.sdk.v2.models.AgentGitSSHKeys import com.coder.gateway.sdk.v2.models.BuildInfo import com.coder.gateway.sdk.v2.models.User import com.coder.gateway.sdk.v2.models.Workspace @@ -24,8 +23,8 @@ import java.time.Instant @Service(Service.Level.APP) class CoderRestClientService { private lateinit var retroRestClient: CoderV2RestFacade + private lateinit var sessionToken: String lateinit var coderURL: URL - lateinit var sessionToken: String lateinit var me: User lateinit var buildVersion: String @@ -33,7 +32,7 @@ class CoderRestClientService { * This must be called before anything else. It will authenticate with coder and retrieve a session token * @throws [AuthenticationException] if authentication failed */ - fun initClientSession(url: URL, token: String): User? { + fun initClientSession(url: URL, token: String): User { val cookieUrl = url.toHttpUrlOrNull()!! val cookieJar = JavaNetCookieJar(CookieManager()).apply { saveFromResponse( @@ -82,16 +81,7 @@ class CoderRestClientService { return workspacesResponse.body()!! } - fun userSSHKeys(): AgentGitSSHKeys { - val sshKeysResponse = retroRestClient.sshKeys().execute() - if (!sshKeysResponse.isSuccessful) { - throw IllegalStateException("Could not retrieve Coder Workspaces:${sshKeysResponse.code()}, reason: ${sshKeysResponse.message()}") - } - - return sshKeysResponse.body()!! - } - - fun buildInfo(): BuildInfo { + private fun buildInfo(): BuildInfo { val buildInfoResponse = retroRestClient.buildInfo().execute() if (!buildInfoResponse.isSuccessful) { throw java.lang.IllegalStateException("Could not retrieve build information for Coder instance $coderURL, reason:${buildInfoResponse.message()}") diff --git a/src/main/kotlin/com/coder/gateway/sdk/convertors/InstantConverter.kt b/src/main/kotlin/com/coder/gateway/sdk/convertors/InstantConverter.kt index 01c544d0..9dbe5846 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/convertors/InstantConverter.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/convertors/InstantConverter.kt @@ -32,7 +32,7 @@ class InstantConverter : JsonSerializer, JsonDeserializer { * @param typeOfSrc the actual type (fully genericized version) of the source object. * @return a JsonElement corresponding to the specified object. */ - override fun serialize(src: Instant?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement? { + override fun serialize(src: Instant?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement { return JsonPrimitive(FORMATTER.format(src)) } diff --git a/src/main/kotlin/com/coder/gateway/sdk/ex/AuthenticationException.kt b/src/main/kotlin/com/coder/gateway/sdk/ex/AuthenticationException.kt index 567db7b4..e241720a 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/ex/AuthenticationException.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/ex/AuthenticationException.kt @@ -2,4 +2,4 @@ package com.coder.gateway.sdk.ex import java.io.IOException -class AuthenticationException(val reason: String) : IOException(reason) \ No newline at end of file +class AuthenticationException(reason: String) : IOException(reason) \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/os.kt b/src/main/kotlin/com/coder/gateway/sdk/os.kt index 71f47e79..df342173 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/os.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/os.kt @@ -19,9 +19,9 @@ fun getOS(): OS? { fun getArch(): Arch? { val arch = System.getProperty("os.arch").toLowerCase() return when { - arch.contains("amd64", true) || arch.contains("x86_64", true) -> Arch.amd64 - arch.contains("arm64", true) || arch.contains("aarch64", true) -> Arch.arm64 - arch.contains("armv7", true) -> Arch.armv7 + arch.contains("amd64", true) || arch.contains("x86_64", true) -> Arch.AMD64 + arch.contains("arm64", true) || arch.contains("aarch64", true) -> Arch.ARM64 + arch.contains("armv7", true) -> Arch.ARMV7 else -> null } } @@ -31,5 +31,5 @@ enum class OS { } enum class Arch { - amd64, arm64, armv7 + AMD64, ARM64, ARMV7 } \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/CoderV1RestFacade.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/CoderV1RestFacade.kt deleted file mode 100644 index 149b701a..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/CoderV1RestFacade.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import retrofit2.Call -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.Path -import retrofit2.http.Query - - -interface CoderV1RestFacade { - - @POST("auth/basic/login") // V2 -> /api/v2/users/login - fun authenticate(@Body loginRequest: LoginRequest): Call - - @GET("api/v0/users/me") // V2 -> /api/v2/users/%s - fun me(@Header("Session-Token") sessionToken: String): Call - - @GET("api/v0/workspaces") // V2 -> /api/v2/workspaces - fun workspaces(@Header("Session-Token") sessionToken: String, @Query("users") users: String): Call> - - @GET("api/v0/users/{userId}/sshkey") //V2 -/api/v2/workspaceagents/me/gitsshkey - fun sshKeys(@Header("Session-Token") sessionToken: String, @Path("userId") userID: String): Call -} \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/CoderWebSocket.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/CoderWebSocket.kt deleted file mode 100644 index 759eb518..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/CoderWebSocket.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.runBlocking -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.WebSocket -import okhttp3.WebSocketListener -import okio.ByteString -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -/** - * Wrapper over OkHttp WebSocket with callbacks converted to coroutines - */ -class CoderWebSocket(val webSocket: WebSocket, val response: Response) { - internal val inChannel = Channel() - - suspend fun receive(): ByteString { - return inChannel.receive() - } - - fun send(byteString: ByteString): Boolean { - return webSocket.send(byteString) - } -} - -suspend fun OkHttpClient.coderWebSocket(request: Request) = suspendCoroutine { - var coderWebSocket: CoderWebSocket? = null - newWebSocket(request, object : WebSocketListener() { - override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { - coderWebSocket!!.inChannel.close() - } - - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - webSocket.close(code, reason) - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - it.resumeWithException(t) - } - - override fun onMessage(webSocket: WebSocket, bytes: ByteString) { - runBlocking { coderWebSocket!!.inChannel.send(bytes) } - } - - override fun onOpen(webSocket: WebSocket, response: Response) { - coderWebSocket = CoderWebSocket(webSocket, response) - it.resume(coderWebSocket!!) - } - }) -} \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/LoginRequest.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/LoginRequest.kt deleted file mode 100644 index 21ced83e..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/LoginRequest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import com.google.gson.annotations.SerializedName - -data class LoginRequest( - @SerializedName("email") val email: String, - @SerializedName("password") val password: String -) \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/LoginResponse.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/LoginResponse.kt deleted file mode 100644 index 5182df8f..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/LoginResponse.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import com.google.gson.annotations.SerializedName - -data class LoginResponse(@SerializedName("session_token") val sessionToken: String) - diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/RebuildMessage.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/RebuildMessage.kt deleted file mode 100644 index 68b42d63..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/RebuildMessage.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import com.google.gson.annotations.SerializedName -import java.time.Duration - -data class RebuildMessage( - @SerializedName("text") val text: String, - @SerializedName("required") val required: Boolean, - @SerializedName("auto_off_threshold") val auto_off_threshold: Duration -) diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/SSHKeys.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/SSHKeys.kt deleted file mode 100644 index f58cf5ba..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/SSHKeys.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import com.google.gson.annotations.SerializedName - -data class SSHKeys(@SerializedName("public_key") val publicKey: String, @SerializedName("private_key") val privateKey: String) \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/User.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/User.kt deleted file mode 100644 index 65749993..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/User.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import com.google.gson.annotations.SerializedName -import java.time.Instant - - -data class User( - @SerializedName("id") val id: String, - @SerializedName("email") val email: String, - @SerializedName("username") val username: String, - @SerializedName("name") val name: String, - @SerializedName("roles") val roles: Set, - @SerializedName("temporary_password") val temporaryPassword: Boolean, - @SerializedName("login_type") val loginType: Boolean, - @SerializedName("key_regenerated_at") val keyRegeneratedAt: Boolean, - @SerializedName("created_at") val createdAt: Instant, - @SerializedName("updated_at") val updatedAt: Instant, -) diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/Workspace.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/Workspace.kt deleted file mode 100644 index d7718dba..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/Workspace.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import com.google.gson.annotations.SerializedName -import java.time.Instant - -data class Workspace( - @SerializedName("id") val id: String, - @SerializedName("name") val name: String, - @SerializedName("image_id") val imageId: String, - @SerializedName("image_tag") val imageTag: String, - @SerializedName("organization_id") val organizationId: String, - @SerializedName("user_id") val userId: String, - @SerializedName("last_built_at") val lastBuiltAt: Instant, - @SerializedName("cpu_cores") val cpuCores: Float, - @SerializedName("memory_gb") val memoryGB: Float, - @SerializedName("disk_gb") val disk_gb: Int, - @SerializedName("gpus") val gpus: Int, - @SerializedName("updating") val updating: Boolean, - @SerializedName("latest_stat") val latestStat: WorkspaceStat, - @SerializedName("rebuild_messages") val rebuildMessages: List, - @SerializedName("created_at") val createdAt: Instant, - @SerializedName("updated_at") val updatedAt: Instant, - @SerializedName("last_opened_at") val lastOpenedAt: Instant, - @SerializedName("last_connection_at") val lastConnectionAt: Instant, - @SerializedName("auto_off_threshold") val autoOffThreshold: Long, - @SerializedName("use_container_vm") val useContainerVM: Boolean, - @SerializedName("resource_pool_id") val resourcePoolId: String, - ) diff --git a/src/main/kotlin/com/coder/gateway/sdk/v1/WorkspaceStat.kt b/src/main/kotlin/com/coder/gateway/sdk/v1/WorkspaceStat.kt deleted file mode 100644 index c182a9d3..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v1/WorkspaceStat.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.coder.gateway.sdk.v1 - -import com.google.gson.annotations.SerializedName -import java.time.Instant - -data class WorkspaceStat( - @SerializedName("time") val time: Instant, - @SerializedName("last_online") val last_online: Instant, - @SerializedName("container_status") val container_status: String, - @SerializedName("stat_error") val stat_error: String, - @SerializedName("cpu_usage") val cpu_usage: Float, - @SerializedName("memory_total") val memory_total: Long, - @SerializedName("memory_usage") val memory_usage: Float, - @SerializedName("disk_total") val disk_total: Long, - @SerializedName("disk_used") val disk_used: Long, -) 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 2887395d..3355d427 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/v2/CoderV2RestFacade.kt @@ -1,24 +1,13 @@ package com.coder.gateway.sdk.v2 -import com.coder.gateway.sdk.v2.models.AgentGitSSHKeys import com.coder.gateway.sdk.v2.models.BuildInfo -import com.coder.gateway.sdk.v2.models.LoginWithPasswordRequest -import com.coder.gateway.sdk.v2.models.LoginWithPasswordResponse import com.coder.gateway.sdk.v2.models.User import com.coder.gateway.sdk.v2.models.Workspace import retrofit2.Call -import retrofit2.http.Body import retrofit2.http.GET -import retrofit2.http.POST interface CoderV2RestFacade { - /** - * Retrieves a session token authenticating with an email and password. - */ - @POST("api/v2/users/login") - fun authenticate(@Body loginRequest: LoginWithPasswordRequest): Call - /** * Retrieves details about the authenticated user. */ @@ -31,9 +20,6 @@ interface CoderV2RestFacade { @GET("api/v2/workspaces") fun workspaces(): Call> - @GET("api/v2/workspaceagents/me/gitsshkey") - fun sshKeys(): Call - @GET("api/v2/buildinfo") fun buildInfo(): Call } \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v2/models/AgentGitSSHKeys.kt b/src/main/kotlin/com/coder/gateway/sdk/v2/models/AgentGitSSHKeys.kt deleted file mode 100644 index 1eead096..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v2/models/AgentGitSSHKeys.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.coder.gateway.sdk.v2.models - -import com.google.gson.annotations.SerializedName - -data class AgentGitSSHKeys(@SerializedName("public_key") val publicKey: String, @SerializedName("private_key") val privateKey: String) \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v2/models/LoginWithPasswordRequest.kt b/src/main/kotlin/com/coder/gateway/sdk/v2/models/LoginWithPasswordRequest.kt deleted file mode 100644 index 51b30792..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v2/models/LoginWithPasswordRequest.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.coder.gateway.sdk.v2.models - -import com.google.gson.annotations.SerializedName - -/** - * Enables callers to authenticate with email and password. - */ -data class LoginWithPasswordRequest( - @SerializedName("email") val email: String, - @SerializedName("password") val password: String -) - - diff --git a/src/main/kotlin/com/coder/gateway/sdk/v2/models/LoginWithPasswordResponse.kt b/src/main/kotlin/com/coder/gateway/sdk/v2/models/LoginWithPasswordResponse.kt deleted file mode 100644 index fcc5018b..00000000 --- a/src/main/kotlin/com/coder/gateway/sdk/v2/models/LoginWithPasswordResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.coder.gateway.sdk.v2.models - -import com.google.gson.annotations.SerializedName - -/** - * contains a session token for the newly authenticated user. - */ -data class LoginWithPasswordResponse(@SerializedName("session_token") val sessionToken: String) \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v2/models/ProvisionerJob.kt b/src/main/kotlin/com/coder/gateway/sdk/v2/models/ProvisionerJob.kt index a950e60d..193e4fc5 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/v2/models/ProvisionerJob.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/v2/models/ProvisionerJob.kt @@ -15,5 +15,21 @@ data class ProvisionerJob( ) enum class ProvisionerJobStatus { - canceled, canceling, failed, pending, running, succeeded + @SerializedName("canceled") + CANCELED, + + @SerializedName("canceling") + CANCELING, + + @SerializedName("failed") + FAILED, + + @SerializedName("pending") + PENDING, + + @SerializedName("running") + RUNNING, + + @SerializedName("succeeded") + SUCCEEDED } \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/sdk/v2/models/WorkspaceBuild.kt b/src/main/kotlin/com/coder/gateway/sdk/v2/models/WorkspaceBuild.kt index 98260223..047ef204 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/v2/models/WorkspaceBuild.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/v2/models/WorkspaceBuild.kt @@ -24,5 +24,12 @@ data class WorkspaceBuild( ) enum class WorkspaceBuildTransition { - start, stop, delete + @SerializedName("start") + START, + + @SerializedName("stop") + STOP, + + @SerializedName("delete") + DELETE } \ No newline at end of file diff --git a/src/main/kotlin/com/coder/gateway/services/CoderRecentWorkspaceConnectionsService.kt b/src/main/kotlin/com/coder/gateway/services/CoderRecentWorkspaceConnectionsService.kt index 10d80d3b..3ce2c78b 100644 --- a/src/main/kotlin/com/coder/gateway/services/CoderRecentWorkspaceConnectionsService.kt +++ b/src/main/kotlin/com/coder/gateway/services/CoderRecentWorkspaceConnectionsService.kt @@ -13,7 +13,7 @@ import com.intellij.openapi.diagnostic.Logger @Service(Service.Level.APP) @State(name = "CoderRecentWorkspaceConnections", storages = [Storage("coder-recent-workspace-connections.xml", roamingType = RoamingType.DISABLED, exportable = true)]) class CoderRecentWorkspaceConnectionsService : PersistentStateComponent { - var myState = RecentWorkspaceConnectionState() + private var myState = RecentWorkspaceConnectionState() fun addRecentConnection(connection: RecentWorkspaceConnection) = myState.add(connection) diff --git a/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectionComponent.kt b/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectionComponent.kt index 9fff2655..fd9bbac9 100644 --- a/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectionComponent.kt +++ b/src/main/kotlin/com/coder/gateway/views/CoderGatewayConnectionComponent.kt @@ -7,7 +7,7 @@ import com.intellij.util.ui.components.BorderLayoutPanel import com.jetbrains.rd.util.lifetime.Lifetime import com.jetbrains.rd.util.lifetime.onTermination -class CoderGatewayConnectionComponent(val lifetime: Lifetime, val url: String) : BorderLayoutPanel() { +class CoderGatewayConnectionComponent(lifetime: Lifetime, val url: String) : BorderLayoutPanel() { private val disposable = Disposer.newDisposable() private val mainPanel = BorderLayoutPanel().apply { add(JBLabel(CoderIcons.LOGO_52), "Center") diff --git a/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt b/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt index bcb1ebb4..a4159b92 100644 --- a/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt +++ b/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt @@ -1,3 +1,5 @@ +@file:Suppress("DialogTitleCapitalization") + package com.coder.gateway.views import com.coder.gateway.CoderGatewayBundle @@ -92,7 +94,7 @@ class CoderGatewayRecentWorkspaceConnectionsView : GatewayRecentConnections { }.horizontalAlign(HorizontalAlign.LEFT).gap(RightGap.SMALL) actionButton(object : DumbAwareAction(CoderGatewayBundle.message("gateway.connector.recentconnections.terminal.button.tooltip"), "", CoderIcons.OPEN_TERMINAL) { override fun actionPerformed(e: AnActionEvent) { - BrowserUtil.browse(recentConnections[0]?.webTerminalLink ?: "") + BrowserUtil.browse(recentConnections[0].webTerminalLink ?: "") } }) } @@ -109,7 +111,7 @@ class CoderGatewayRecentWorkspaceConnectionsView : GatewayRecentConnections { "type" to "coder", "coder_workspace_hostname" to "${connectionDetails.coderWorkspaceHostname}", "project_path" to connectionDetails.projectPath!!, - "ide_product_code" to "${product.productCode}", + "ide_product_code" to product.productCode, "ide_build_number" to "${connectionDetails.ideBuildNumber}", "ide_download_link" to "${connectionDetails.downloadSource}" ) diff --git a/src/main/kotlin/com/coder/gateway/views/LazyBrowserLink.kt b/src/main/kotlin/com/coder/gateway/views/LazyBrowserLink.kt index 70a899f8..a7d47e79 100644 --- a/src/main/kotlin/com/coder/gateway/views/LazyBrowserLink.kt +++ b/src/main/kotlin/com/coder/gateway/views/LazyBrowserLink.kt @@ -3,14 +3,19 @@ package com.coder.gateway.views import com.intellij.icons.AllIcons import com.intellij.ide.BrowserUtil import com.intellij.ide.IdeBundle +import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.DefaultActionGroup import com.intellij.openapi.actionSystem.ex.ActionManagerEx +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState import com.intellij.openapi.ide.CopyPasteManager import com.intellij.openapi.project.DumbAwareAction import com.intellij.ui.components.ActionLink import org.jetbrains.annotations.Nls import java.awt.datatransfer.StringSelection +import java.util.concurrent.ForkJoinPool +import java.util.function.Consumer import javax.swing.Icon class LazyBrowserLink(icon: Icon, @Nls text: String) : ActionLink() { @@ -24,12 +29,25 @@ class LazyBrowserLink(icon: Icon, @Nls text: String) : ActionLink() { field = value if (value != null) { addActionListener { BrowserUtil.browse(value) } - ActionManagerEx.doWithLazyActionManager { instance -> + + doWithLazyActionManager { instance -> val group = DefaultActionGroup(OpenLinkInBrowser(value), CopyLinkAction(value)) componentPopupMenu = instance.createActionPopupMenu("popup@browser.link.context.menu", group).component } } } + + private fun doWithLazyActionManager(whatToDo: Consumer) { + val created = ApplicationManager.getApplication().getServiceIfCreated(ActionManager::class.java) + if (created == null) { + ForkJoinPool.commonPool().execute { + val actionManager: ActionManager = ActionManagerEx.getInstanceEx() + ApplicationManager.getApplication().invokeLater({ whatToDo.accept(actionManager) }, ModalityState.any()) + } + } else { + whatToDo.accept(created) + } + } } private class CopyLinkAction(val url: String) : DumbAwareAction(IdeBundle.messagePointer("action.text.copy.link.address"), AllIcons.Actions.Copy) { 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 b4239a89..6a42bef0 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderAuthStepView.kt @@ -1,9 +1,16 @@ +@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.* +import com.coder.gateway.sdk.CoderCLIManager +import com.coder.gateway.sdk.CoderRestClientService +import com.coder.gateway.sdk.OS +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 @@ -19,7 +26,11 @@ 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.* +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 @@ -71,9 +82,10 @@ class CoderAuthStepView : CoderWorkspacesWizardStep, Disposable { BrowserUtil.browse(model.coderURL.toURL().withPath("/login?redirect=%2Fcli-auth")) val pastedToken = askToken() - if (pastedToken?.isNullOrBlank() == true || coderClient.initClientSession(model.coderURL.toURL(), pastedToken) == null) { + if (pastedToken.isNullOrBlank()) { return false } + coderClient.initClientSession(model.coderURL.toURL(), pastedToken) model.token = pastedToken model.buildVersion = coderClient.buildVersion diff --git a/src/main/kotlin/com/coder/gateway/views/steps/CoderLocateRemoteProjectStepView.kt b/src/main/kotlin/com/coder/gateway/views/steps/CoderLocateRemoteProjectStepView.kt index e6bc4077..936bc459 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderLocateRemoteProjectStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderLocateRemoteProjectStepView.kt @@ -124,7 +124,7 @@ class CoderLocateRemoteProjectStepView : CoderWorkspacesWizardStep, Disposable { .flatMap { CachingProductsJsonWrapper.getAvailableIdes(it, workspaceOS) } .map { ide -> IdeWithStatus(ide.product, ide.buildNumber, IdeStatus.DOWNLOAD, ide.downloadLink, ide.presentableVersion) } - if (idesWithStatus.isNullOrEmpty()) { + if (idesWithStatus.isEmpty()) { logger.warn("Could not resolve any IDE for workspace ${selectedWorkspace.name}, probably $workspaceOS is not supported by Gateway") } else { cbIDE.remove(spinner) @@ -144,9 +144,9 @@ class CoderLocateRemoteProjectStepView : CoderWorkspacesWizardStep, Disposable { "type" to "coder", "coder_workspace_hostname" to "coder.${wizardModel.selectedWorkspace?.name}", "project_path" to tfProject.text, - "ide_product_code" to "${selectedIDE.product.productCode}", - "ide_build_number" to "${selectedIDE.buildNumber}", - "ide_download_link" to "${selectedIDE.source}", + "ide_product_code" to selectedIDE.product.productCode, + "ide_build_number" to selectedIDE.buildNumber, + "ide_download_link" to selectedIDE.source, "web_terminal_link" to "${terminalLink.url}" ) ) diff --git a/src/main/kotlin/com/coder/gateway/views/steps/WorkspaceCellRenderer.kt b/src/main/kotlin/com/coder/gateway/views/steps/WorkspaceCellRenderer.kt index c2c40300..e7170a6c 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/WorkspaceCellRenderer.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/WorkspaceCellRenderer.kt @@ -51,27 +51,27 @@ class WorkspaceCellRenderer : ListCellRenderer { } private fun iconForStatus(workspace: Workspace) = when (workspace.latestBuild.job.status) { - ProvisionerJobStatus.succeeded -> if (workspace.latestBuild.workspaceTransition == WorkspaceBuildTransition.start) GREEN_CIRCLE else RED_CIRCLE - ProvisionerJobStatus.running -> when (workspace.latestBuild.workspaceTransition) { - WorkspaceBuildTransition.start, WorkspaceBuildTransition.stop, WorkspaceBuildTransition.delete -> GRAY_CIRCLE + ProvisionerJobStatus.SUCCEEDED -> if (workspace.latestBuild.workspaceTransition == WorkspaceBuildTransition.START) GREEN_CIRCLE else RED_CIRCLE + ProvisionerJobStatus.RUNNING -> when (workspace.latestBuild.workspaceTransition) { + WorkspaceBuildTransition.START, WorkspaceBuildTransition.STOP, WorkspaceBuildTransition.DELETE -> GRAY_CIRCLE } else -> RED_CIRCLE } private fun labelForStatus(workspace: Workspace) = when (workspace.latestBuild.job.status) { - ProvisionerJobStatus.pending -> "◍ Queued" - ProvisionerJobStatus.running -> when (workspace.latestBuild.workspaceTransition) { - WorkspaceBuildTransition.start -> "⦿ Starting" - WorkspaceBuildTransition.stop -> "◍ Stopping" - WorkspaceBuildTransition.delete -> "⦸ Deleting" + ProvisionerJobStatus.PENDING -> "◍ Queued" + ProvisionerJobStatus.RUNNING -> when (workspace.latestBuild.workspaceTransition) { + WorkspaceBuildTransition.START -> "⦿ Starting" + WorkspaceBuildTransition.STOP -> "◍ Stopping" + WorkspaceBuildTransition.DELETE -> "⦸ Deleting" } - ProvisionerJobStatus.succeeded -> when (workspace.latestBuild.workspaceTransition) { - WorkspaceBuildTransition.start -> "⦿ Running" - WorkspaceBuildTransition.stop -> "◍ Stopped" - WorkspaceBuildTransition.delete -> "⦸ Deleted" + ProvisionerJobStatus.SUCCEEDED -> when (workspace.latestBuild.workspaceTransition) { + WorkspaceBuildTransition.START -> "⦿ Running" + WorkspaceBuildTransition.STOP -> "◍ Stopped" + WorkspaceBuildTransition.DELETE -> "⦸ Deleted" } - ProvisionerJobStatus.canceling -> "◍ Canceling action" - ProvisionerJobStatus.canceled -> "◍ Canceled action" - ProvisionerJobStatus.failed -> "ⓧ Failed" + ProvisionerJobStatus.CANCELING -> "◍ Canceling action" + ProvisionerJobStatus.CANCELED -> "◍ Canceled action" + ProvisionerJobStatus.FAILED -> "ⓧ Failed" } } \ No newline at end of file