@@ -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 ..." )
@@ -465,16 +473,16 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
465
473
)
466
474
try {
467
475
this .indicator.text = " Authenticating client..."
468
- authenticate(deploymentURL, token)
476
+ authenticate(deploymentURL, token.first )
469
477
// Remember these in order to default to them for future attempts.
470
478
appPropertiesService.setValue(CODER_URL_KEY , deploymentURL.toString())
471
- appPropertiesService.setValue(SESSION_TOKEN , token)
479
+ appPropertiesService.setValue(SESSION_TOKEN , token.first )
472
480
473
481
this .indicator.text = " Downloading Coder CLI..."
474
482
cliManager.downloadCLI()
475
483
476
484
this .indicator.text = " Authenticating Coder CLI..."
477
- cliManager.login(token)
485
+ cliManager.login(token.first )
478
486
479
487
this .indicator.text = " Retrieving workspaces..."
480
488
loadWorkspaces()
@@ -521,22 +529,29 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
521
529
}
522
530
523
531
/* *
524
- * Open a dialog for providing the token. Show the existing token so the
525
- * user can validate it if a previous connection failed. Open a browser to
526
- * the auth page if openBrowser is true and useExisting is false. If
527
- * useExisting is true then populate the dialog with the token on disk if
528
- * there is one and it matches the url (this will overwrite the provided
529
- * token). Return the token submitted by the user.
532
+ * Open a dialog for providing the token. Show any existing token so the
533
+ * user can validate it if a previous connection failed. If we are not
534
+ * retrying and the user has not checked the existing token box then open a
535
+ * browser to the auth page. If the user has checked the existing token box
536
+ * then populate the dialog with the token on disk (this will overwrite any
537
+ * other existing token) unless this is a retry to avoid clobbering the
538
+ * token that just failed. Return the token submitted by the user.
530
539
*/
531
- private fun askToken (url : URL , token : String , openBrowser : Boolean , useExisting : Boolean ): String? {
532
- var existingToken = token
540
+ private fun askToken (
541
+ url : URL ,
542
+ token : Pair <String , TokenSource >? ,
543
+ isRetry : Boolean ,
544
+ useExisting : Boolean ,
545
+ ): Pair <String , TokenSource >? {
546
+ var (existingToken, tokenSource) = token ? : Pair (" " , TokenSource .USER )
533
547
val getTokenUrl = url.withPath(" /login?redirect=%2Fcli-auth" )
534
- if (openBrowser && ! useExisting) {
548
+ if (! isRetry && ! useExisting) {
535
549
BrowserUtil .browse(getTokenUrl)
536
- } else if (useExisting) {
550
+ } else if (! isRetry && useExisting) {
537
551
val (u, t) = CoderCLIManager .readConfig()
538
- if (url == u?.toURL() && ! t.isNullOrBlank()) {
539
- logger.info(" Injecting valid token from CLI config" )
552
+ if (url == u?.toURL() && ! t.isNullOrBlank() && t != existingToken) {
553
+ logger.info(" Injecting token from CLI config" )
554
+ tokenSource = TokenSource .CONFIG
540
555
existingToken = t
541
556
}
542
557
}
@@ -549,11 +564,32 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
549
564
CoderGatewayBundle .message(" gateway.connector.view.login.token.label" ),
550
565
getTokenUrl.toString()
551
566
)
552
- sessionTokenTextField = textField().applyToComponent {
553
- text = existingToken
554
- minimumSize = Dimension (520 , - 1 )
555
- }.component
556
- }
567
+ sessionTokenTextField = textField()
568
+ .applyToComponent {
569
+ text = existingToken
570
+ minimumSize = Dimension (520 , - 1 )
571
+ }.component
572
+ }.layout(RowLayout .PARENT_GRID )
573
+ row {
574
+ cell() // To align with the text box.
575
+ cell(
576
+ ComponentPanelBuilder .createCommentComponent(
577
+ CoderGatewayBundle .message(
578
+ if (isRetry) " gateway.connector.view.workspaces.token.rejected"
579
+ else if (tokenSource == TokenSource .CONFIG ) " gateway.connector.view.workspaces.token.injected"
580
+ else if (existingToken.isNotBlank()) " gateway.connector.view.workspaces.token.comment"
581
+ else " gateway.connector.view.workspaces.token.none"
582
+ ),
583
+ false ,
584
+ - 1 ,
585
+ true
586
+ ).applyIf(isRetry) {
587
+ apply {
588
+ foreground = UIUtil .getErrorForeground()
589
+ }
590
+ }
591
+ )
592
+ }.layout(RowLayout .PARENT_GRID )
557
593
}
558
594
AppIcon .getInstance().requestAttention(null , true )
559
595
if (! dialog(
@@ -566,7 +602,13 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
566
602
}
567
603
tokenFromUser = sessionTokenTextField.text
568
604
}, ModalityState .any())
569
- return tokenFromUser
605
+ if (tokenFromUser.isNullOrBlank()) {
606
+ return null
607
+ }
608
+ if (tokenFromUser != existingToken) {
609
+ tokenSource = TokenSource .USER
610
+ }
611
+ return Pair (tokenFromUser!! , tokenSource)
570
612
}
571
613
572
614
private fun triggerWorkspacePolling (fetchNow : Boolean ) {
0 commit comments