@@ -64,10 +64,16 @@ import kotlinx.coroutines.cancel
64
64
import kotlinx.coroutines.delay
65
65
import kotlinx.coroutines.isActive
66
66
import kotlinx.coroutines.launch
67
+ import kotlinx.coroutines.runBlocking
67
68
import kotlinx.coroutines.withContext
68
69
import org.zeroturnaround.exec.ProcessExecutor
69
70
import java.awt.Component
70
71
import java.awt.Dimension
72
+ import java.awt.event.MouseEvent
73
+ import java.awt.event.MouseListener
74
+ import java.awt.event.MouseMotionListener
75
+ import java.awt.font.TextAttribute
76
+ import java.awt.font.TextAttribute.UNDERLINE_ON
71
77
import javax.swing.Icon
72
78
import javax.swing.JTable
73
79
import javax.swing.JTextField
@@ -80,6 +86,8 @@ private const val CODER_URL_KEY = "coder-url"
80
86
81
87
private const val SESSION_TOKEN = " session-token"
82
88
89
+ private const val MOUSE_OVER_TEMPLATE_NAME_COLUMN_ON_ROW = " MOUSE_OVER_TEMPLATE_NAME_COLUMN_ON_ROW"
90
+
83
91
class CoderWorkspacesStepView (val enableNextButtonCallback : (Boolean ) -> Unit ) : CoderWorkspacesWizardStep, Disposable {
84
92
private val cs = CoroutineScope (Dispatchers .Main )
85
93
private var localWizardModel = CoderWorkspacesWizardModel ()
@@ -123,6 +131,49 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
123
131
}
124
132
updateWorkspaceActions()
125
133
}
134
+
135
+ addMouseListener(object : MouseListener {
136
+ override fun mouseClicked (e : MouseEvent ? ) {
137
+ if (e?.source is TableView <* >) {
138
+ val tblView = e.source as TableView <WorkspaceAgentModel >
139
+ val col = tblView.selectedColumn
140
+ val workspace = tblView.selectedObject
141
+
142
+ if (col == 2 && workspace != null ) {
143
+ BrowserUtil .browse(coderClient.coderURL.toURI().resolve(" /templates/${workspace.templateName} " ))
144
+ }
145
+ }
146
+ }
147
+
148
+ override fun mousePressed (e : MouseEvent ? ) {
149
+ }
150
+
151
+ override fun mouseReleased (e : MouseEvent ? ) {
152
+ }
153
+
154
+ override fun mouseEntered (e : MouseEvent ? ) {
155
+ }
156
+
157
+ override fun mouseExited (e : MouseEvent ? ) {
158
+ }
159
+ })
160
+ addMouseMotionListener(object : MouseMotionListener {
161
+ override fun mouseMoved (e : MouseEvent ? ) {
162
+ if (e?.source is TableView <* >) {
163
+ val tblView = e.source as TableView <WorkspaceAgentModel >
164
+ val row = tblView.rowAtPoint(e.point)
165
+ if (tblView.columnAtPoint(e.point) == 2 && row in 0 until tblView.listTableModel.rowCount) {
166
+ tblView.putClientProperty(MOUSE_OVER_TEMPLATE_NAME_COLUMN_ON_ROW , row)
167
+ } else {
168
+ tblView.putClientProperty(MOUSE_OVER_TEMPLATE_NAME_COLUMN_ON_ROW , - 1 )
169
+ }
170
+ }
171
+
172
+ }
173
+
174
+ override fun mouseDragged (e : MouseEvent ? ) {
175
+ }
176
+ })
126
177
}
127
178
128
179
private val goToDashboardAction = GoToDashboardAction ()
@@ -349,12 +400,20 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
349
400
350
401
val authTask = object : Task .Modal (null , CoderGatewayBundle .message(" gateway.connector.view.coder.workspaces.cli.downloader.dialog.title" ), false ) {
351
402
override fun run (pi : ProgressIndicator ) {
352
-
353
403
pi.apply {
354
404
isIndeterminate = false
355
- text = " Downloading coder cli ..."
405
+ text = " Retrieving Workspaces ..."
356
406
fraction = 0.1
357
407
}
408
+ runBlocking {
409
+ loadWorkspaces()
410
+ }
411
+
412
+ pi.apply {
413
+ isIndeterminate = false
414
+ text = " Downloading Coder CLI..."
415
+ fraction = 0.3
416
+ }
358
417
359
418
cliManager.downloadCLI()
360
419
if (getOS() != OS .WINDOWS ) {
@@ -363,7 +422,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
363
422
logger.info(" chmod +x ${cliManager.localCli.toAbsolutePath()} $chmodOutput " )
364
423
}
365
424
pi.apply {
366
- text = " Configuring coder cli ..."
425
+ text = " Configuring Coder CLI ..."
367
426
fraction = 0.5
368
427
}
369
428
@@ -374,7 +433,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
374
433
logger.info(" Result of `${localWizardModel.localCliPath} config-ssh --yes --use-previous-options`: $sshConfigOutput " )
375
434
376
435
pi.apply {
377
- text = " Remove old coder cli versions..."
436
+ text = " Remove old Coder CLI versions..."
378
437
fraction = 0.9
379
438
}
380
439
cliManager.removeOldCli()
@@ -417,35 +476,50 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
417
476
418
477
poller = cs.launch {
419
478
while (isActive) {
420
- loadWorkspaces()
421
479
delay(5000 )
480
+ loadWorkspaces()
422
481
}
423
482
}
424
483
}
425
484
426
485
private suspend fun loadWorkspaces () {
427
- val workspaceList = withContext(Dispatchers .IO ) {
486
+ withContext(Dispatchers .IO ) {
487
+ val timeBeforeRequestingWorkspaces = System .currentTimeMillis()
428
488
try {
429
- return @withContext coderClient.workspaces().collectAgents()
489
+ val ws = coderClient.workspaces()
490
+ val timeAfterRequestingWorkspaces = System .currentTimeMillis()
491
+ logger.info(" Retrieving the workspaces took: ${timeAfterRequestingWorkspaces - timeBeforeRequestingWorkspaces} millis" )
492
+ ws.resolveAndDisplayAgents()
430
493
} catch (e: Exception ) {
431
494
logger.error(" Could not retrieve workspaces for ${coderClient.me.username} on ${coderClient.coderURL} . Reason: $e " )
432
- emptyList()
433
495
}
434
496
}
497
+ }
435
498
436
- withContext(Dispatchers .Main ) {
437
- val selectedWorkspace = tableOfWorkspaces.selectedObject?.name
438
- listTableModelOfWorkspaces.items = workspaceList
439
- if (selectedWorkspace != null ) {
440
- tableOfWorkspaces.selectItem(selectedWorkspace)
499
+ private fun List<Workspace>.resolveAndDisplayAgents () {
500
+ this .forEach { workspace ->
501
+ cs.launch(Dispatchers .IO ) {
502
+ val timeBeforeRequestingAgents = System .currentTimeMillis()
503
+ workspace.agentModels().forEach { am ->
504
+ withContext(Dispatchers .Main ) {
505
+ val selectedWorkspace = tableOfWorkspaces.selectedObject?.name
506
+ if (listTableModelOfWorkspaces.indexOf(am) >= 0 ) {
507
+ val index = listTableModelOfWorkspaces.indexOf(am)
508
+ listTableModelOfWorkspaces.setItem(index, am)
509
+ } else {
510
+ listTableModelOfWorkspaces.addRow(am)
511
+ }
512
+ if (selectedWorkspace != null ) {
513
+ tableOfWorkspaces.selectItem(selectedWorkspace)
514
+ }
515
+ }
516
+ }
517
+ val timeAfterRequestingAgents = System .currentTimeMillis()
518
+ logger.info(" Retrieving the agents for ${workspace.name} took: ${timeAfterRequestingAgents - timeBeforeRequestingAgents} millis" )
441
519
}
442
520
}
443
521
}
444
522
445
- private fun List<Workspace>.collectAgents (): List <WorkspaceAgentModel > {
446
- return this .flatMap { it.agentModels() }.toList()
447
- }
448
-
449
523
private fun Workspace.agentModels (): List <WorkspaceAgentModel > {
450
524
return try {
451
525
val agents = coderClient.workspaceAgentsByTemplate(this )
@@ -569,9 +643,10 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
569
643
override fun isCenterAlignment () = true
570
644
571
645
override fun getTableCellRendererComponent (table : JTable ? , value : Any? , selected : Boolean , focus : Boolean , row : Int , column : Int ): Component {
572
- return super .getTableCellRendererComponent(table, value, selected, focus, row, column).apply {
573
- border = JBUI .Borders .empty(10 , 10 )
646
+ super .getTableCellRendererComponent(table, value, selected, focus, row, column).apply {
647
+ border = JBUI .Borders .empty(10 )
574
648
}
649
+ return this
575
650
}
576
651
}
577
652
}
@@ -590,6 +665,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
590
665
text = value
591
666
}
592
667
font = JBFont .h3().asBold()
668
+ border = JBUI .Borders .empty()
593
669
return this
594
670
}
595
671
}
@@ -602,13 +678,27 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
602
678
}
603
679
604
680
override fun getRenderer (item : WorkspaceAgentModel ? ): TableCellRenderer {
681
+ val simpleH3 = JBFont .h3()
682
+
683
+ val h3AttributesWithUnderlining = simpleH3.attributes as MutableMap <TextAttribute , Any >
684
+ h3AttributesWithUnderlining[TextAttribute .UNDERLINE ] = UNDERLINE_ON
685
+ val underlinedH3 = JBFont .h3().deriveFont(h3AttributesWithUnderlining)
605
686
return object : DefaultTableCellRenderer () {
606
687
override fun getTableCellRendererComponent (table : JTable , value : Any , isSelected : Boolean , hasFocus : Boolean , row : Int , column : Int ): Component {
607
688
super .getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column)
608
689
if (value is String ) {
609
690
text = value
610
691
}
611
- font = JBFont .h3()
692
+ border = JBUI .Borders .empty()
693
+
694
+ if (table.getClientProperty(MOUSE_OVER_TEMPLATE_NAME_COLUMN_ON_ROW ) != null ) {
695
+ val mouseOverRow = table.getClientProperty(MOUSE_OVER_TEMPLATE_NAME_COLUMN_ON_ROW ) as Int
696
+ if (mouseOverRow >= 0 && mouseOverRow == row) {
697
+ font = underlinedH3
698
+ return this
699
+ }
700
+ }
701
+ font = simpleH3
612
702
return this
613
703
}
614
704
}
@@ -628,6 +718,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
628
718
text = value
629
719
}
630
720
font = JBFont .h3()
721
+ border = JBUI .Borders .empty()
631
722
return this
632
723
}
633
724
}
@@ -647,6 +738,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
647
738
text = value
648
739
}
649
740
font = JBFont .h3()
741
+ border = JBUI .Borders .empty()
650
742
foreground = (table.model as ListTableModel <WorkspaceAgentModel >).getRowValue(row).statusColor()
651
743
return this
652
744
}
0 commit comments