Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type" : "bugfix",
"description" : "Fix issue where IDE freezes when logging into Amazon Q"
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class AmazonQToolWindowFactory : ToolWindowFactory, DumbAware {
override fun activeConnectionChanged(newConnection: ToolkitConnection?) {
ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let { qConn ->
openMeetQPage(project)
QRegionProfileManager.getInstance().validateProfile(project)
}
prepareChatContent(project, qPanel)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.profile.QProfileSwitchIn
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener
import software.aws.toolkits.jetbrains.utils.satisfiesKt
import software.aws.toolkits.jetbrains.utils.xmlElement
import java.net.URI
import java.util.function.Consumer
Expand Down Expand Up @@ -105,6 +106,23 @@ class QRegionProfileManagerTest {
assertThat(sut.activeProfile(project)).isNull()
}

@Test
fun `data is cleared when user logs out`() {
sut.switchProfile(project, QRegionProfile(arn = "arn", profileName = "foo_profile"), QProfileSwitchIntent.User)
assertThat(sut.activeProfile(project)).isEqualTo(QRegionProfile(arn = "arn", profileName = "foo_profile"))

ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let {
if (it is AwsBearerTokenConnection) {
logoutFromSsoConnection(project, it)
}
}

assertThat(sut.state).satisfiesKt {
assertThat(it.connectionIdToActiveProfile).isEmpty()
assertThat(it.connectionIdToProfileList).isEmpty()
}
}

@Test
fun `switch should send message onProfileChanged for active switch`() {
var cnt = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
package software.aws.toolkits.jetbrains.services.amazonq.profile

import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.BaseState
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.intellij.util.xmlb.annotations.MapAnnotation
import com.intellij.util.xmlb.annotations.Property
import software.amazon.awssdk.core.SdkClient
Expand All @@ -25,6 +27,7 @@
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.sono.isSono
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProviderListener
import software.aws.toolkits.jetbrains.core.region.AwsRegionProvider
import software.aws.toolkits.jetbrains.utils.notifyInfo
import software.aws.toolkits.resources.AmazonQBundle.message
Expand All @@ -40,9 +43,23 @@

// Map to store connectionId to its active profile
private val connectionIdToActiveProfile = Collections.synchronizedMap<String, QRegionProfile>(mutableMapOf())
private val connectionIdToProfileList = mutableMapOf<String, Int>()
private val connectionIdToProfileCount = mutableMapOf<String, Int>()

Check warning on line 46 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt#L46

Added line #L46 was not covered by tests

init {
ApplicationManager.getApplication().messageBus.connect(this)
.subscribe(
BearerTokenProviderListener.TOPIC,
object : BearerTokenProviderListener {

Check warning on line 52 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt#L48-L52

Added lines #L48 - L52 were not covered by tests
override fun invalidate(providerId: String) {
connectionIdToActiveProfile.remove(providerId)
connectionIdToProfileCount.remove(providerId)
}

Check warning on line 56 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt#L54-L56

Added lines #L54 - L56 were not covered by tests
}
)
}

Check warning on line 59 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt#L59

Added line #L59 was not covered by tests

// should be call on project startup to validate if profile is still active
@RequiresBackgroundThread
fun validateProfile(project: Project) {
val conn = getIdcConnectionOrNull(project)
val selected = activeProfile(project) ?: return
Expand Down Expand Up @@ -78,7 +95,7 @@
switchProfile(project, mappedProfiles.first(), intent = QProfileSwitchIntent.Update)
}
mappedProfiles.takeIf { it.isNotEmpty() }?.also {
connectionIdToProfileList[connection.id] = it.size
connectionIdToProfileCount[connection.id] = it.size

Check warning on line 98 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt#L98

Added line #L98 was not covered by tests
} ?: error("You don't have access to the resource")
} catch (e: Exception) {
LOG.warn(e) { "Failed to list region profiles: ${e.message}" }
Expand Down Expand Up @@ -110,7 +127,7 @@
Telemetry.amazonq.didSelectProfile.use { span ->
span.source(intent.value)
.amazonQProfileRegion(newProfile.region)
.profileCount(connectionIdToProfileList[conn.id])
.profileCount(connectionIdToProfileCount[conn.id])

Check warning on line 130 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt#L130

Added line #L130 was not covered by tests
.ssoRegion(conn.region)
.credentialStartUrl(conn.startUrl)
.result(MetricResult.Succeeded)
Expand Down Expand Up @@ -139,13 +156,13 @@

// for each idc connection, user should have a profile, otherwise should show the profile selection error page
fun isPendingProfileSelection(project: Project): Boolean = getIdcConnectionOrNull(project)?.let { conn ->
val profileCounts = connectionIdToProfileList[conn.id] ?: 0
val profileCounts = connectionIdToProfileCount[conn.id] ?: 0
val activeProfile = connectionIdToActiveProfile[conn.id]
profileCounts == 0 || (profileCounts > 1 && activeProfile?.arn.isNullOrEmpty())
} ?: false

fun shouldDisplayProfileInfo(project: Project): Boolean = getIdcConnectionOrNull(project)?.let { conn ->
(connectionIdToProfileList[conn.id] ?: 0) > 1
(connectionIdToProfileCount[conn.id] ?: 0) > 1
} ?: false

fun getQClientSettings(project: Project): TokenConnectionSettings {
Expand Down Expand Up @@ -191,16 +208,16 @@
override fun getState(): QProfileState {
val state = QProfileState()
state.connectionIdToActiveProfile.putAll(this.connectionIdToActiveProfile)
state.connectionIdToProfileList.putAll(this.connectionIdToProfileList)
state.connectionIdToProfileList.putAll(this.connectionIdToProfileCount)

Check warning on line 211 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt#L211

Added line #L211 was not covered by tests
return state
}

override fun loadState(state: QProfileState) {
connectionIdToActiveProfile.clear()
connectionIdToActiveProfile.putAll(state.connectionIdToActiveProfile)

connectionIdToProfileList.clear()
connectionIdToProfileList.putAll(state.connectionIdToProfileList)
connectionIdToProfileCount.clear()
connectionIdToProfileCount.putAll(state.connectionIdToProfileList)

Check warning on line 220 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt#L219-L220

Added lines #L219 - L220 were not covered by tests
}
}

Expand Down
Loading