Skip to content

Commit f7c7687

Browse files
authored
fix(amazonq): load profiles async using AsyncComboBox instead of randomly popping up dialog when done (#5550)
1 parent 3a66543 commit f7c7687

File tree

3 files changed

+77
-61
lines changed

3 files changed

+77
-61
lines changed

plugins/amazonq/shared/jetbrains-community/resources/software/aws/toolkits/resources/AmazonQBundle.properties

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
action.q.hello.description=Hello description
21
amazonqInlineChat.hint.edit = Edit
32
amazonqInlineChat.popup.accept=Accept \u23CE
43
amazonqInlineChat.popup.cancel=Cancel \u238B
@@ -10,9 +9,9 @@ amazonqInlineChat.popup.title=Enter Instructions for Q
109
amazonq.refresh.panel=Refresh Chat Session
1110
amazonq.title=Amazon Q
1211
amazonq.workspace.settings.open.prompt=Workspace index is now enabled. You can disable it from Amazon Q settings.
13-
action.q.profile.usage.text=You changed profile
14-
action.q.profile.usage=You're using the '<b>{0}</b>' profile for Amazon Q.
15-
action.q.switchProfiles.text=Change profile
12+
action.q.profile.usage.text=You changed your profile
13+
action.q.profile.usage=You''re using the ''<b>{0}</b>'' profile for Amazon Q.
14+
action.q.switchProfiles.text=Change Profile
1615
action.q.switchProfiles.dialog.text=Amazon Q Developer Profile
1716
action.q.switchProfiles.dialog.account.label=Account: {0}
1817
action.q.switchProfiles.dialog.panel.text=Change your Q Developer profile

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/actions/QSwitchProfilesAction.kt

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,10 @@ import com.intellij.icons.AllIcons
77
import com.intellij.openapi.actionSystem.ActionUpdateThread
88
import com.intellij.openapi.actionSystem.AnAction
99
import com.intellij.openapi.actionSystem.AnActionEvent
10-
import com.intellij.openapi.application.ApplicationManager
1110
import com.intellij.openapi.project.DumbAware
12-
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
13-
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
14-
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
15-
import software.aws.toolkits.jetbrains.services.amazonq.profile.QProfileSwitchIntent
1611
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileDialog
1712
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
1813
import software.aws.toolkits.resources.AmazonQBundle.message
19-
import software.aws.toolkits.telemetry.MetricResult
20-
import software.aws.toolkits.telemetry.Telemetry
2114

2215
class QSwitchProfilesAction : AnAction(message("action.q.switchProfiles.text")), DumbAware {
2316

@@ -29,30 +22,9 @@ class QSwitchProfilesAction : AnAction(message("action.q.switchProfiles.text")),
2922

3023
override fun actionPerformed(e: AnActionEvent) {
3124
val project = e.project ?: return
32-
ApplicationManager.getApplication().executeOnPooledThread {
33-
val profiles = try {
34-
QRegionProfileManager.getInstance().listRegionProfiles(project)
35-
} catch (e: Exception) {
36-
val conn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) as? AwsBearerTokenConnection
37-
Telemetry.amazonq.didSelectProfile.use { span ->
38-
span.source(QProfileSwitchIntent.User.value)
39-
.amazonQProfileRegion(QRegionProfileManager.getInstance().activeProfile(project)?.region ?: "not-set")
40-
.ssoRegion(conn?.region)
41-
.credentialStartUrl(conn?.startUrl)
42-
.result(MetricResult.Failed)
43-
.reason(e.message)
44-
}
45-
throw e
46-
}
47-
?: error("Attempted to fetch profiles while there does not exist")
48-
val selectedProfile = QRegionProfileManager.getInstance().activeProfile(project) ?: profiles[0]
49-
ApplicationManager.getApplication().invokeLater {
50-
QRegionProfileDialog(
51-
project,
52-
profiles = profiles,
53-
selectedProfile = selectedProfile
54-
).show()
55-
}
56-
}
25+
QRegionProfileDialog(
26+
project,
27+
selectedProfile = QRegionProfileManager.getInstance().activeProfile(project)
28+
).show()
5729
}
5830
}

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileDialog.kt

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,61 @@ import com.intellij.icons.AllIcons
77
import com.intellij.openapi.project.Project
88
import com.intellij.openapi.ui.DialogPanel
99
import com.intellij.openapi.ui.DialogWrapper
10+
import com.intellij.ui.ColoredListCellRenderer
11+
import com.intellij.ui.SimpleTextAttributes
12+
import com.intellij.ui.dsl.builder.AlignX
1013
import com.intellij.ui.dsl.builder.BottomGap
11-
import com.intellij.ui.dsl.builder.bind
14+
import com.intellij.ui.dsl.builder.bindItem
1215
import com.intellij.ui.dsl.builder.panel
16+
import com.intellij.ui.dsl.builder.toNullableProperty
1317
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
1418
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
1519
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
1620
import software.aws.toolkits.jetbrains.core.help.HelpIds
21+
import software.aws.toolkits.jetbrains.ui.AsyncComboBox
22+
import software.aws.toolkits.jetbrains.utils.ui.selected
1723
import software.aws.toolkits.resources.AmazonQBundle.message
24+
import software.aws.toolkits.resources.AwsCoreBundle
1825
import software.aws.toolkits.telemetry.MetricResult
1926
import software.aws.toolkits.telemetry.Telemetry
2027
import javax.swing.JComponent
28+
import javax.swing.JList
29+
30+
data class QRegionProfileDialogState(
31+
var selectedProfile: QRegionProfile? = null,
32+
)
2133

2234
class QRegionProfileDialog(
2335
private var project: Project,
24-
private var profiles: List<QRegionProfile>,
25-
private var selectedProfile: QRegionProfile, // default
36+
val state: QRegionProfileDialogState = QRegionProfileDialogState(),
37+
private var selectedProfile: QRegionProfile?,
2638
) : DialogWrapper(project) {
2739

40+
private val renderer = object : ColoredListCellRenderer<QRegionProfile>() {
41+
override fun customizeCellRenderer(
42+
list: JList<out QRegionProfile>,
43+
value: QRegionProfile?,
44+
index: Int,
45+
selected: Boolean,
46+
hasFocus: Boolean,
47+
) {
48+
value?.let {
49+
append(
50+
if (it == selectedProfile) {
51+
"${it.profileName} - ${it.region} (connected)"
52+
} else {
53+
"${it.profileName} - ${it.region}"
54+
},
55+
SimpleTextAttributes.REGULAR_ATTRIBUTES
56+
)
57+
58+
append(" " + message("action.q.switchProfiles.dialog.account.label", it.accountId), SimpleTextAttributes.GRAY_SMALL_ATTRIBUTES)
59+
}
60+
}
61+
}
62+
63+
private val combo = AsyncComboBox<QRegionProfile>(customRenderer = renderer)
64+
2865
private val panel: DialogPanel by lazy {
2966
panel {
3067
row { label(message("action.q.switchProfiles.dialog.panel.text")).bold() }
@@ -36,32 +73,40 @@ class QRegionProfileDialog(
3673
}
3774
separator().bottomGap(BottomGap.MEDIUM)
3875

39-
buttonsGroup {
40-
profiles.forEach { profile ->
41-
row {
42-
radioButton("", profile)
43-
44-
panel {
45-
val regionDisplay = if (profile == selectedProfile) {
46-
"${profile.profileName} - ${profile.region} (connected)"
47-
} else {
48-
"${profile.profileName} - ${profile.region}"
49-
}
50-
row { label(regionDisplay) }
51-
row {
52-
label(message("action.q.switchProfiles.dialog.account.label", profile.accountId)).applyToComponent {
53-
font = font.deriveFont(font.size2D - 2.0f)
54-
}
55-
}
56-
}
57-
}.bottomGap(BottomGap.MEDIUM)
76+
combo.proposeModelUpdate { model ->
77+
try {
78+
QRegionProfileManager.getInstance().listRegionProfiles(project)?.forEach {
79+
model.addElement(it)
80+
} ?: error("Attempted to fetch profiles while there does not exist")
81+
82+
model.selectedItem = selectedProfile
83+
} catch (e: Exception) {
84+
val conn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) as? AwsBearerTokenConnection
85+
Telemetry.amazonq.didSelectProfile.use { span ->
86+
span.source(QProfileSwitchIntent.User.value)
87+
.amazonQProfileRegion(QRegionProfileManager.getInstance().activeProfile(project)?.region ?: "not-set")
88+
.ssoRegion(conn?.region)
89+
.credentialStartUrl(conn?.startUrl)
90+
.result(MetricResult.Failed)
91+
.reason(e.message)
92+
}
93+
throw e
5894
}
59-
}.bind({ selectedOption }, { selectedOption = it })
95+
}
96+
97+
row {
98+
cell(combo)
99+
.align(AlignX.FILL)
100+
.errorOnApply(AwsCoreBundle.message("gettingstarted.setup.error.not_selected")) { it.selected() == null }
101+
.bindItem(state::selectedProfile.toNullableProperty())
102+
}
60103

61104
separator().bottomGap(BottomGap.MEDIUM)
62105
}
63106
}
64-
private var selectedOption: QRegionProfile = selectedProfile // user selected
107+
108+
private val selectedOption
109+
get() = state.selectedProfile // user selected
65110

66111
init {
67112
title = message("action.q.switchProfiles.dialog.text")
@@ -87,7 +132,7 @@ class QRegionProfileDialog(
87132
Telemetry.amazonq.didSelectProfile.use { span ->
88133
span.source(QProfileSwitchIntent.User.value)
89134
.amazonQProfileRegion(profileManager.activeProfile(project)?.region ?: "not-set")
90-
.profileCount(profiles.size)
135+
.profileCount(combo.model.size)
91136
.ssoRegion(conn?.region)
92137
.credentialStartUrl(conn?.startUrl)
93138
.result(MetricResult.Cancelled)

0 commit comments

Comments
 (0)