@@ -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 {
@@ -107,6 +113,7 @@ class CoderLocateRemoteProjectStepView(private val disableNextAction: () -> Unit
107113 override val nextActionText = CoderGatewayBundle .message(" gateway.connector.view.coder.remoteproject.next.text" )
108114
109115 override fun onInit (wizardModel : CoderWorkspacesWizardModel ) {
116+ ideComboBoxModel.removeAllElements()
110117 wizard = wizardModel
111118 val selectedWorkspace = wizardModel.selectedWorkspace
112119 if (selectedWorkspace == null ) {
@@ -118,61 +125,73 @@ class CoderLocateRemoteProjectStepView(private val disableNextAction: () -> Unit
118125 titleLabel.text = CoderGatewayBundle .message(" gateway.connector.view.coder.remoteproject.choose.text" , selectedWorkspace.name)
119126 terminalLink.url = " ${coderClient.coderURL} /@${coderClient.me.username} /${selectedWorkspace.name} /terminal"
120127
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))
128+ ideResolvingJob = cs.launch {
129+ try {
130+ retrieveIDES(selectedWorkspace)
131+ } catch (e: Exception ) {
132+ when (e) {
133+ is InterruptedException -> Unit
134+ is CancellationException -> Unit
135+ else -> {
136+ logger.error(" Could not resolve any IDE for workspace ${selectedWorkspace.name} . Reason: $e " )
137+ withContext(Dispatchers .Main ) {
138+ disableNextAction()
139+ cbIDE.renderer = object : ColoredListCellRenderer <IdeWithStatus >() {
140+ override fun customizeCellRenderer (list : JList <out IdeWithStatus >, value : IdeWithStatus ? , index : Int , isSelected : Boolean , cellHasFocus : Boolean ) {
141+ background = UIUtil .getListBackground(isSelected, cellHasFocus)
142+ icon = UIUtil .getBalloonErrorIcon()
143+ append(CoderGatewayBundle .message(" gateway.connector.view.coder.remoteproject.ide.error.text" , selectedWorkspace.name))
144+ }
145+ }
146+ }
146147 }
147148 }
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- }
149+ }
150+ }
151+ }
159152
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- }
153+ private suspend fun retrieveIDES (selectedWorkspace : WorkspaceAgentModel ) {
154+ logger.info(" Retrieving available IDE's for ${selectedWorkspace.name} workspace..." )
155+ val hostAccessor = HighLevelHostAccessor .create(
156+ RemoteCredentialsHolder ().apply {
157+ setHost(" coder.${selectedWorkspace.name} " )
158+ userName = " coder"
159+ authType = AuthType .OPEN_SSH
160+ },
161+ true
162+ )
163+ val workspaceOS = if (selectedWorkspace.agentOS != null && selectedWorkspace.agentArch != null ) toDeployedOS(selectedWorkspace.agentOS, selectedWorkspace.agentArch) else withContext(Dispatchers .IO ) {
164+ hostAccessor.guessOs()
165+ }
168166
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 {
167+ logger.info(" Resolved OS and Arch for ${selectedWorkspace.name} is: $workspaceOS " )
168+ val installedIdesJob = cs.async(Dispatchers .IO ) {
169+ hostAccessor.getInstalledIDEs().map { ide -> IdeWithStatus (ide.product, ide.buildNumber, IdeStatus .ALREADY_INSTALLED , null , ide.pathToIde, ide.presentableVersion, ide.remoteDevType) }
170+ }
171+ val idesWithStatusJob = cs.async(Dispatchers .IO ) {
172+ IntelliJPlatformProduct .values()
173+ .filter { it.showInGateway }
174+ .flatMap { CachingProductsJsonWrapper .getInstance().getAvailableIdes(it, workspaceOS) }
175+ .map { ide -> IdeWithStatus (ide.product, ide.buildNumber, IdeStatus .DOWNLOAD , ide.download, null , ide.presentableVersion, ide.remoteDevType) }
176+ }
172177
173- ideComboBoxModel.addAll(idesWithStatus)
174- cbIDE.selectedIndex = 0
175- }
178+ val installedIdes = installedIdesJob.await()
179+ val idesWithStatus = idesWithStatusJob.await()
180+ if (installedIdes.isEmpty()) {
181+ logger.info(" No IDE is installed in workspace ${selectedWorkspace.name} " )
182+ } else {
183+ withContext(Dispatchers .Main ) {
184+ ideComboBoxModel.addAll(installedIdes)
185+ cbIDE.selectedIndex = 0
186+ }
187+ }
188+
189+ if (idesWithStatus.isEmpty()) {
190+ logger.warn(" Could not resolve any IDE for workspace ${selectedWorkspace.name} , probably $workspaceOS is not supported by Gateway" )
191+ } else {
192+ withContext(Dispatchers .Main ) {
193+ ideComboBoxModel.addAll(idesWithStatus)
194+ cbIDE.selectedIndex = 0
176195 }
177196 }
178197 }
@@ -201,6 +220,7 @@ class CoderLocateRemoteProjectStepView(private val disableNextAction: () -> Unit
201220
202221 override fun onNext (wizardModel : CoderWorkspacesWizardModel ): Boolean {
203222 val selectedIDE = cbIDE.selectedItem ? : return false
223+ logger.info(" Going to launch the IDE" )
204224 cs.launch {
205225 GatewayUI .getInstance().connect(
206226 selectedIDE
@@ -213,12 +233,16 @@ class CoderLocateRemoteProjectStepView(private val disableNextAction: () -> Unit
213233 return true
214234 }
215235
216- override fun dispose () {
217- cs.cancel()
236+ override fun onPrevious () {
237+ super .onPrevious()
238+ logger.info(" Going back to Workspace view" )
239+ cs.launch {
240+ ideResolvingJob.cancelAndJoin()
241+ }
218242 }
219243
220- companion object {
221- val logger = Logger .getInstance( CoderLocateRemoteProjectStepView :: class .java.simpleName )
244+ override fun dispose () {
245+ cs.cancel( )
222246 }
223247
224248 private class IDEComboBox (model : ComboBoxModel <IdeWithStatus >) : ComboBox<IdeWithStatus>(model) {
@@ -258,4 +282,8 @@ class CoderLocateRemoteProjectStepView(private val disableNextAction: () -> Unit
258282 }
259283 }
260284 }
285+
286+ companion object {
287+ val logger = Logger .getInstance(CoderLocateRemoteProjectStepView ::class .java.simpleName)
288+ }
261289}
0 commit comments