@@ -3,6 +3,7 @@ package com.coder.gateway.views.steps
33import com.coder.gateway.CoderGatewayBundle
44import com.coder.gateway.icons.CoderIcons
55import com.coder.gateway.models.CoderWorkspacesWizardModel
6+ import com.coder.gateway.models.WorkspaceAgentModel
67import com.coder.gateway.sdk.Arch
78import com.coder.gateway.sdk.CoderRestClientService
89import com.coder.gateway.sdk.OS
@@ -38,10 +39,13 @@ import com.jetbrains.gateway.ssh.HighLevelHostAccessor
3839import com.jetbrains.gateway.ssh.IdeStatus
3940import com.jetbrains.gateway.ssh.IdeWithStatus
4041import com.jetbrains.gateway.ssh.IntelliJPlatformProduct
42+ import kotlinx.coroutines.CancellationException
4143import kotlinx.coroutines.CoroutineScope
4244import kotlinx.coroutines.Dispatchers
45+ import kotlinx.coroutines.Job
4346import kotlinx.coroutines.async
4447import kotlinx.coroutines.cancel
48+ import kotlinx.coroutines.cancelAndJoin
4549import kotlinx.coroutines.launch
4650import kotlinx.coroutines.withContext
4751import java.awt.Component
@@ -67,6 +71,8 @@ class CoderLocateRemoteProjectStepView(private val disableNextAction: () -> Unit
6771 private lateinit var tfProject: JBTextField
6872 private lateinit var terminalLink: LazyBrowserLink
6973
74+ private lateinit var ideResolvingJob: Job
75+
7076 override val component = panel {
7177 indent {
7278 row {
@@ -118,61 +124,73 @@ class CoderLocateRemoteProjectStepView(private val disableNextAction: () -> Unit
118124 titleLabel.text = CoderGatewayBundle .message(" gateway.connector.view.coder.remoteproject.choose.text" , selectedWorkspace.name)
119125 terminalLink.url = " ${coderClient.coderURL} /@${coderClient.me.username} /${selectedWorkspace.name} /terminal"
120126
121- cs.launch {
122- logger.info(" Retrieving available IDE's for ${selectedWorkspace.name} workspace..." )
123- val hostAccessor = HighLevelHostAccessor .create(
124- RemoteCredentialsHolder ().apply {
125- setHost(" coder.${selectedWorkspace.name} " )
126- userName = " coder"
127- authType = AuthType .OPEN_SSH
128- },
129- true
130- )
131- val workspaceOS = if (selectedWorkspace.agentOS != null && selectedWorkspace.agentArch != null ) toDeployedOS(selectedWorkspace.agentOS, selectedWorkspace.agentArch) else withContext(Dispatchers .IO ) {
132- try {
133- hostAccessor.guessOs()
134- } catch (e: Exception ) {
135- logger.error(" Could not resolve any IDE for workspace ${selectedWorkspace.name} . Reason: $e " )
136- null
137- }
138- }
139- if (workspaceOS == null ) {
140- disableNextAction()
141- cbIDE.renderer = object : ColoredListCellRenderer <IdeWithStatus >() {
142- override fun customizeCellRenderer (list : JList <out IdeWithStatus >, value : IdeWithStatus ? , index : Int , isSelected : Boolean , cellHasFocus : Boolean ) {
143- background = UIUtil .getListBackground(isSelected, cellHasFocus)
144- icon = UIUtil .getBalloonErrorIcon()
145- append(CoderGatewayBundle .message(" gateway.connector.view.coder.remoteproject.ide.error.text" , selectedWorkspace.name))
127+ ideResolvingJob = cs.launch {
128+ try {
129+ retrieveIDES(selectedWorkspace)
130+ } catch (e: Exception ) {
131+ when (e) {
132+ is InterruptedException -> Unit
133+ is CancellationException -> Unit
134+ else -> {
135+ logger.error(" Could not resolve any IDE for workspace ${selectedWorkspace.name} . Reason: $e " )
136+ withContext(Dispatchers .Main ) {
137+ disableNextAction()
138+ cbIDE.renderer = object : ColoredListCellRenderer <IdeWithStatus >() {
139+ override fun customizeCellRenderer (list : JList <out IdeWithStatus >, value : IdeWithStatus ? , index : Int , isSelected : Boolean , cellHasFocus : Boolean ) {
140+ background = UIUtil .getListBackground(isSelected, cellHasFocus)
141+ icon = UIUtil .getBalloonErrorIcon()
142+ append(CoderGatewayBundle .message(" gateway.connector.view.coder.remoteproject.ide.error.text" , selectedWorkspace.name))
143+ }
144+ }
145+ }
146146 }
147147 }
148- } else {
149- logger.info(" Resolved OS and Arch for ${selectedWorkspace.name} is: $workspaceOS " )
150- val installedIdesJob = async(Dispatchers .IO ) {
151- hostAccessor.getInstalledIDEs().map { ide -> IdeWithStatus (ide.product, ide.buildNumber, IdeStatus .ALREADY_INSTALLED , null , ide.pathToIde, ide.presentableVersion, ide.remoteDevType) }
152- }
153- val idesWithStatusJob = async(Dispatchers .IO ) {
154- IntelliJPlatformProduct .values()
155- .filter { it.showInGateway }
156- .flatMap { CachingProductsJsonWrapper .getInstance().getAvailableIdes(it, workspaceOS) }
157- .map { ide -> IdeWithStatus (ide.product, ide.buildNumber, IdeStatus .DOWNLOAD , ide.download, null , ide.presentableVersion, ide.remoteDevType) }
158- }
148+ }
149+ }
150+ }
159151
160- val installedIdes = installedIdesJob.await()
161- val idesWithStatus = idesWithStatusJob.await()
162- if (installedIdes.isEmpty()) {
163- logger.info(" No IDE is installed in workspace ${selectedWorkspace.name} " )
164- } else {
165- ideComboBoxModel.addAll(installedIdes)
166- cbIDE.selectedIndex = 0
167- }
152+ private suspend fun retrieveIDES (selectedWorkspace : WorkspaceAgentModel ) {
153+ logger.info(" Retrieving available IDE's for ${selectedWorkspace.name} workspace..." )
154+ val hostAccessor = HighLevelHostAccessor .create(
155+ RemoteCredentialsHolder ().apply {
156+ setHost(" coder.${selectedWorkspace.name} " )
157+ userName = " coder"
158+ authType = AuthType .OPEN_SSH
159+ },
160+ true
161+ )
162+ val workspaceOS = if (selectedWorkspace.agentOS != null && selectedWorkspace.agentArch != null ) toDeployedOS(selectedWorkspace.agentOS, selectedWorkspace.agentArch) else withContext(Dispatchers .IO ) {
163+ hostAccessor.guessOs()
164+ }
168165
169- if (idesWithStatus.isEmpty()) {
170- logger.warn(" Could not resolve any IDE for workspace ${selectedWorkspace.name} , probably $workspaceOS is not supported by Gateway" )
171- } else {
166+ logger.info(" Resolved OS and Arch for ${selectedWorkspace.name} is: $workspaceOS " )
167+ val installedIdesJob = cs.async(Dispatchers .IO ) {
168+ hostAccessor.getInstalledIDEs().map { ide -> IdeWithStatus (ide.product, ide.buildNumber, IdeStatus .ALREADY_INSTALLED , null , ide.pathToIde, ide.presentableVersion, ide.remoteDevType) }
169+ }
170+ val idesWithStatusJob = cs.async(Dispatchers .IO ) {
171+ IntelliJPlatformProduct .values()
172+ .filter { it.showInGateway }
173+ .flatMap { CachingProductsJsonWrapper .getInstance().getAvailableIdes(it, workspaceOS) }
174+ .map { ide -> IdeWithStatus (ide.product, ide.buildNumber, IdeStatus .DOWNLOAD , ide.download, null , ide.presentableVersion, ide.remoteDevType) }
175+ }
172176
173- ideComboBoxModel.addAll(idesWithStatus)
174- cbIDE.selectedIndex = 0
175- }
177+ val installedIdes = installedIdesJob.await()
178+ val idesWithStatus = idesWithStatusJob.await()
179+ if (installedIdes.isEmpty()) {
180+ logger.info(" No IDE is installed in workspace ${selectedWorkspace.name} " )
181+ } else {
182+ withContext(Dispatchers .Main ) {
183+ ideComboBoxModel.addAll(installedIdes)
184+ cbIDE.selectedIndex = 0
185+ }
186+ }
187+
188+ if (idesWithStatus.isEmpty()) {
189+ logger.warn(" Could not resolve any IDE for workspace ${selectedWorkspace.name} , probably $workspaceOS is not supported by Gateway" )
190+ } else {
191+ withContext(Dispatchers .Main ) {
192+ ideComboBoxModel.addAll(idesWithStatus)
193+ cbIDE.selectedIndex = 0
176194 }
177195 }
178196 }
@@ -213,6 +231,13 @@ class CoderLocateRemoteProjectStepView(private val disableNextAction: () -> Unit
213231 return true
214232 }
215233
234+ override fun onPrevious () {
235+ super .onPrevious()
236+ cs.launch {
237+ ideResolvingJob.cancelAndJoin()
238+ }
239+ }
240+
216241 override fun dispose () {
217242 cs.cancel()
218243 }
0 commit comments