@@ -3,6 +3,7 @@ package com.coder.gateway.views.steps
3
3
import com.coder.gateway.CoderGatewayBundle
4
4
import com.coder.gateway.icons.CoderIcons
5
5
import com.coder.gateway.models.CoderWorkspacesWizardModel
6
+ import com.coder.gateway.models.TokenSource
6
7
import com.coder.gateway.models.WorkspaceAgentModel
7
8
import com.coder.gateway.models.WorkspaceAgentStatus
8
9
import com.coder.gateway.models.WorkspaceAgentStatus.FAILED
@@ -56,10 +57,12 @@ import com.intellij.ui.dsl.builder.bindSelected
56
57
import com.intellij.ui.dsl.builder.bindText
57
58
import com.intellij.ui.dsl.builder.panel
58
59
import com.intellij.ui.table.TableView
60
+ import com.intellij.util.applyIf
59
61
import com.intellij.util.ui.ColumnInfo
60
62
import com.intellij.util.ui.JBFont
61
63
import com.intellij.util.ui.JBUI
62
64
import com.intellij.util.ui.ListTableModel
65
+ import com.intellij.util.ui.UIUtil
63
66
import com.intellij.util.ui.table.IconTableCellRenderer
64
67
import com.jetbrains.rd.util.lifetime.LifetimeDefinition
65
68
import kotlinx.coroutines.CoroutineScope
@@ -348,7 +351,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
348
351
349
352
override fun onInit (wizardModel : CoderWorkspacesWizardModel ) {
350
353
listTableModelOfWorkspaces.items = emptyList()
351
- if (localWizardModel.coderURL.isNotBlank() && localWizardModel.token.isNotBlank() ) {
354
+ if (localWizardModel.coderURL.isNotBlank() && localWizardModel.token != null ) {
352
355
triggerWorkspacePolling(true )
353
356
} else {
354
357
val (url, token) = readStorageOrConfig()
@@ -357,10 +360,10 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
357
360
tfUrl?.text = url
358
361
}
359
362
if (! token.isNullOrBlank()) {
360
- localWizardModel.token = token
363
+ localWizardModel.token = Pair ( token, TokenSource . CONFIG )
361
364
}
362
365
if (! url.isNullOrBlank() && ! token.isNullOrBlank()) {
363
- connect(url.toURL(), token)
366
+ connect(url.toURL(), Pair ( token, TokenSource . CONFIG ) )
364
367
}
365
368
}
366
369
updateWorkspaceActions()
@@ -417,20 +420,21 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
417
420
* If the token is invalid abort and start over from askTokenAndConnect()
418
421
* unless retry is false.
419
422
*/
420
- private fun askTokenAndConnect (openBrowser : Boolean = true) {
423
+ private fun askTokenAndConnect (isRetry : Boolean = false) {
424
+ val oldURL = localWizardModel.coderURL.toURL()
421
425
component.apply () // Force bindings to be filled.
426
+ val newURL = localWizardModel.coderURL.toURL()
422
427
val pastedToken = askToken(
423
- localWizardModel.coderURL.toURL(),
424
- localWizardModel.token,
425
- openBrowser,
428
+ newURL,
429
+ // If this is a new URL there is no point in trying to use the same
430
+ // token.
431
+ if (oldURL == newURL) localWizardModel.token else null ,
432
+ isRetry,
426
433
localWizardModel.useExistingToken,
427
- )
428
- if (pastedToken.isNullOrBlank()) {
429
- return // User aborted.
430
- }
434
+ ) ? : return // User aborted.
431
435
localWizardModel.token = pastedToken
432
- connect(localWizardModel.coderURL.toURL(), localWizardModel.token ) {
433
- askTokenAndConnect(false )
436
+ connect(newURL, pastedToken ) {
437
+ askTokenAndConnect(true )
434
438
}
435
439
}
436
440
@@ -444,7 +448,11 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
444
448
*
445
449
* If the token is invalid invoke onAuthFailure.
446
450
*/
447
- private fun connect (deploymentURL : URL , token : String , onAuthFailure : (() -> Unit )? = null): Job {
451
+ private fun connect (
452
+ deploymentURL : URL ,
453
+ token : Pair <String , TokenSource >,
454
+ onAuthFailure : (() -> Unit )? = null,
455
+ ): Job {
448
456
// Clear out old deployment details.
449
457
poller?.cancel()
450
458
tableOfWorkspaces.setEmptyState(" Connecting to $deploymentURL ..." )
@@ -464,16 +472,16 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
464
472
)
465
473
try {
466
474
this .indicator.text = " Authenticating client..."
467
- authenticate(deploymentURL, token)
475
+ authenticate(deploymentURL, token.first )
468
476
// Remember these in order to default to them for future attempts.
469
477
appPropertiesService.setValue(CODER_URL_KEY , deploymentURL.toString())
470
- appPropertiesService.setValue(SESSION_TOKEN , token)
478
+ appPropertiesService.setValue(SESSION_TOKEN , token.first )
471
479
472
480
this .indicator.text = " Downloading Coder CLI..."
473
481
cliManager.downloadCLI()
474
482
475
483
this .indicator.text = " Authenticating Coder CLI..."
476
- cliManager.login(token)
484
+ cliManager.login(token.first )
477
485
478
486
this .indicator.text = " Retrieving workspaces..."
479
487
loadWorkspaces()
@@ -520,22 +528,29 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
520
528
}
521
529
522
530
/* *
523
- * Open a dialog for providing the token. Show the existing token so the
524
- * user can validate it if a previous connection failed. Open a browser to
525
- * the auth page if openBrowser is true and useExisting is false. If
526
- * useExisting is true then populate the dialog with the token on disk if
527
- * there is one and it matches the url (this will overwrite the provided
528
- * token). Return the token submitted by the user.
531
+ * Open a dialog for providing the token. Show any existing token so the
532
+ * user can validate it if a previous connection failed. If we are not
533
+ * retrying and the user has not checked the existing token box then open a
534
+ * browser to the auth page. If the user has checked the existing token box
535
+ * then populate the dialog with the token on disk (this will overwrite any
536
+ * other existing token) unless this is a retry to avoid clobbering the
537
+ * token that just failed. Return the token submitted by the user.
529
538
*/
530
- private fun askToken (url : URL , token : String , openBrowser : Boolean , useExisting : Boolean ): String? {
531
- var existingToken = token
539
+ private fun askToken (
540
+ url : URL ,
541
+ token : Pair <String , TokenSource >? ,
542
+ isRetry : Boolean ,
543
+ useExisting : Boolean ,
544
+ ): Pair <String , TokenSource >? {
545
+ var (existingToken, tokenSource) = token ? : Pair (" " , TokenSource .USER )
532
546
val getTokenUrl = url.withPath(" /login?redirect=%2Fcli-auth" )
533
- if (openBrowser && ! useExisting) {
547
+ if (! isRetry && ! useExisting) {
534
548
BrowserUtil .browse(getTokenUrl)
535
- } else if (useExisting) {
549
+ } else if (! isRetry && useExisting) {
536
550
val (u, t) = CoderCLIManager .readConfig()
537
- if (url == u?.toURL() && ! t.isNullOrBlank()) {
538
- logger.info(" Injecting valid token from CLI config" )
551
+ if (url == u?.toURL() && ! t.isNullOrBlank() && t != existingToken) {
552
+ logger.info(" Injecting token from CLI config" )
553
+ tokenSource = TokenSource .CONFIG
539
554
existingToken = t
540
555
}
541
556
}
@@ -548,11 +563,32 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
548
563
CoderGatewayBundle .message(" gateway.connector.view.login.token.label" ),
549
564
getTokenUrl.toString()
550
565
)
551
- sessionTokenTextField = textField().applyToComponent {
552
- text = existingToken
553
- minimumSize = Dimension (520 , - 1 )
554
- }.component
555
- }
566
+ sessionTokenTextField = textField()
567
+ .applyToComponent {
568
+ text = existingToken
569
+ minimumSize = Dimension (520 , - 1 )
570
+ }.component
571
+ }.layout(RowLayout .PARENT_GRID )
572
+ row {
573
+ cell() // To align with the text box.
574
+ cell(
575
+ ComponentPanelBuilder .createCommentComponent(
576
+ CoderGatewayBundle .message(
577
+ if (isRetry) " gateway.connector.view.workspaces.token.rejected"
578
+ else if (tokenSource == TokenSource .CONFIG ) " gateway.connector.view.workspaces.token.injected"
579
+ else if (existingToken.isNotBlank()) " gateway.connector.view.workspaces.token.comment"
580
+ else " gateway.connector.view.workspaces.token.none"
581
+ ),
582
+ false ,
583
+ - 1 ,
584
+ true
585
+ ).applyIf(isRetry) {
586
+ apply {
587
+ foreground = UIUtil .getErrorForeground()
588
+ }
589
+ }
590
+ )
591
+ }.layout(RowLayout .PARENT_GRID )
556
592
}
557
593
AppIcon .getInstance().requestAttention(null , true )
558
594
if (! dialog(
@@ -565,7 +601,13 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
565
601
}
566
602
tokenFromUser = sessionTokenTextField.text
567
603
}, ModalityState .any())
568
- return tokenFromUser
604
+ if (tokenFromUser.isNullOrBlank()) {
605
+ return null
606
+ }
607
+ if (tokenFromUser != existingToken) {
608
+ tokenSource = TokenSource .USER
609
+ }
610
+ return Pair (tokenFromUser!! , tokenSource)
569
611
}
570
612
571
613
private fun triggerWorkspacePolling (fetchNow : Boolean ) {
0 commit comments