summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Baker-Malone <jbakermalone@google.com>2023-12-27 12:42:17 -0800
committerJoe Baker-Malone <jbakermalone@google.com>2024-02-01 16:13:54 -0800
commit3e8b82d991ef81c666ef0666f321f9c63e3f6474 (patch)
treee996aa7d5574c81c07ca3e398410549ef807db13
parentfdba33c5e06dbb1a6b266f7e12d52dc2144f0802 (diff)
downloadtools-3e8b82d991ef81c666ef0666f321f9c63e3f6474.tar.gz
Implement login button
Test: added Bug: 308497310 Change-Id: Ieedc33864f5ec3eae4c2331e0eaee7293d3e7691
-rw-r--r--google-login-plugin/src/com/google/gct/login2/LoginFeature.kt11
-rw-r--r--google-login-plugin/src/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUi.kt47
-rw-r--r--google-login-plugin/testSrc/com/google/gct/login2/LoginUsersRule.kt2
-rw-r--r--google-login-plugin/testSrc/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUiTest.kt51
4 files changed, 97 insertions, 14 deletions
diff --git a/google-login-plugin/src/com/google/gct/login2/LoginFeature.kt b/google-login-plugin/src/com/google/gct/login2/LoginFeature.kt
index ed75cc8..60e22ed 100644
--- a/google-login-plugin/src/com/google/gct/login2/LoginFeature.kt
+++ b/google-login-plugin/src/com/google/gct/login2/LoginFeature.kt
@@ -18,6 +18,7 @@ package com.google.gct.login2
import com.google.api.client.auth.oauth2.Credential
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.extensions.ExtensionPointName
+import javax.swing.JComponent
/**
* Extension representing a feature that requires google login with certain [oAuthScopes]. The
@@ -51,7 +52,15 @@ interface LoginFeature {
fun isLoggedIn() = GoogleLoginService.instance.isLoggedIn(this)
- fun logInAsync() = GoogleLoginService.instance.logInAsync(features = setOf(this))
+ fun logInAsync(
+ preferredUser: PreferredUser = PreferredUser.ActiveUser,
+ parentComponent: JComponent? = null,
+ ) =
+ GoogleLoginService.instance.logInAsync(
+ features = setOf(this),
+ preferredUser = preferredUser,
+ parentComponent = parentComponent,
+ )
}
class UserInfoEnforcedFeature : LoginFeature {
diff --git a/google-login-plugin/src/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUi.kt b/google-login-plugin/src/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUi.kt
index f6a5f80..a1b32ad 100644
--- a/google-login-plugin/src/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUi.kt
+++ b/google-login-plugin/src/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUi.kt
@@ -36,7 +36,6 @@ import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.DataKey
import com.intellij.openapi.application.ModalityState
-import com.intellij.openapi.application.invokeLater
import com.intellij.openapi.components.service
import com.intellij.openapi.options.ConfigurableUi
import com.intellij.openapi.ui.VerticalFlowLayout
@@ -72,9 +71,9 @@ import javax.swing.JButton
import javax.swing.JComponent
import javax.swing.JPanel
import javax.swing.ListSelectionModel
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import org.jetbrains.annotations.VisibleForTesting
internal val SELECTED_USER_KEY = DataKey.create<CredentialedUser>("login.settings.selected.user")
@@ -82,8 +81,9 @@ internal val SELECTED_USER_KEY = DataKey.create<CredentialedUser>("login.setting
internal class GoogleLoginApplicationSettingsConfigurableUi : ConfigurableUi<Unit>, Disposable {
private val avatars = concurrentMapOf<Image, Icon>()
- private val scope = AndroidCoroutineScope(this)
+ private val scope = AndroidCoroutineScope(this, AndroidDispatchers.uiThread(ModalityState.any()))
private val service = service<GoogleLoginService>()
+ private val selectedUserFlow: MutableStateFlow<CredentialedUser?> = MutableStateFlow(null)
override fun reset(settings: Unit) {}
@@ -122,9 +122,7 @@ internal class GoogleLoginApplicationSettingsConfigurableUi : ConfigurableUi<Uni
component.add(emptyComponent, "empty")
scope.launch {
service<GoogleLoginService>().allUsersFlow.collect { users ->
- invokeLater(ModalityState.any()) {
- cardLayout.show(component, if (users.isEmpty()) "empty" else "main")
- }
+ cardLayout.show(component, if (users.isEmpty()) "empty" else "main")
}
}
@@ -138,6 +136,11 @@ internal class GoogleLoginApplicationSettingsConfigurableUi : ConfigurableUi<Uni
val list =
JBList<CredentialedUser>(DefaultListModel()).apply {
selectionMode = ListSelectionModel.SINGLE_SELECTION
+ addListSelectionListener { event ->
+ if (!event.valueIsAdjusting) {
+ selectedUserFlow.value = this@apply.selectedValue
+ }
+ }
}
DataManager.registerDataProvider(list) { key ->
@@ -177,11 +180,9 @@ internal class GoogleLoginApplicationSettingsConfigurableUi : ConfigurableUi<Uni
service.allUsersFlow
.combine(service.activeUserFlow) { _, _ -> }
.collect {
- withContext(AndroidDispatchers.uiThread(ModalityState.any())) {
- refreshUserListModel(list)
- result.preferredSize = Dimension(list.preferredSize.width + 4, 0)
- result.revalidate()
- }
+ refreshUserListModel(list)
+ result.preferredSize = Dimension(list.preferredSize.width + 4, 0)
+ result.revalidate()
}
}
return result
@@ -299,6 +300,17 @@ internal class GoogleLoginApplicationSettingsConfigurableUi : ConfigurableUi<Uni
myBorder = JBUI.Borders.empty(0, 1)
append(feature.name, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES)
}
+ val allowButton =
+ JButton().apply {
+ addActionListener {
+ feature.logInAsync(
+ selectedUserFlow.value?.email?.let { PreferredUser.User(it) } ?: PreferredUser.None,
+ parentComponent = this@apply,
+ )
+ }
+ }
+ updateAllowButton(feature, allowButton)
+ scope.launch { selectedUserFlow.collect { updateAllowButton(feature, allowButton) } }
val renderer =
JPanel(BorderLayout()).apply {
border = JBUI.Borders.empty(0, 8)
@@ -311,8 +323,7 @@ internal class GoogleLoginApplicationSettingsConfigurableUi : ConfigurableUi<Uni
)
add(
JPanel(BorderLayout()).apply {
- // TODO: hook up button
- add(JButton("Allow"), BorderLayout.NORTH)
+ add(allowButton, BorderLayout.NORTH)
add(Box.createVerticalGlue(), BorderLayout.CENTER)
},
BorderLayout.EAST,
@@ -341,6 +352,16 @@ internal class GoogleLoginApplicationSettingsConfigurableUi : ConfigurableUi<Uni
)
return renderer
}
+
+ private fun updateAllowButton(feature: LoginFeature, button: JButton) {
+ if (selectedUserFlow.value?.isLoggedIn(feature) == true) {
+ button.text = "Allowed"
+ button.isEnabled = false
+ } else {
+ button.isEnabled = selectedUserFlow.value != null
+ button.text = "Allow"
+ }
+ }
}
internal object SwitchUserAction :
diff --git a/google-login-plugin/testSrc/com/google/gct/login2/LoginUsersRule.kt b/google-login-plugin/testSrc/com/google/gct/login2/LoginUsersRule.kt
index e427ad9..0dfa410 100644
--- a/google-login-plugin/testSrc/com/google/gct/login2/LoginUsersRule.kt
+++ b/google-login-plugin/testSrc/com/google/gct/login2/LoginUsersRule.kt
@@ -56,6 +56,8 @@ class LoginUsersRule : NamedExternalResource() {
// logged in with all features
fun setActiveUser(email: String) = setActiveUser(email, LoginFeature.EP_NAME.extensionList)
+ fun getUser(email: String): CredentialedUser? = loginService.allUsersFlow.value[email]
+
override fun after(description: Description) {
Disposer.dispose(disposable)
}
diff --git a/google-login-plugin/testSrc/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUiTest.kt b/google-login-plugin/testSrc/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUiTest.kt
index c99072b..e7a5afd 100644
--- a/google-login-plugin/testSrc/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUiTest.kt
+++ b/google-login-plugin/testSrc/com/google/gct/login2/settings/GoogleLoginApplicationSettingsConfigurableUiTest.kt
@@ -49,6 +49,7 @@ import com.intellij.ui.components.AnActionLink
import com.intellij.ui.components.BrowserLink
import com.intellij.ui.components.JBLabel
import com.intellij.ui.components.JBList
+import com.intellij.util.ui.UIUtil
import icons.GoogleLoginIcons
import java.awt.Color
import java.awt.GradientPaint
@@ -333,4 +334,54 @@ class GoogleLoginApplicationSettingsConfigurableUiTest {
}
createModalDialogAndInteractWithIt({ dialog.show() }) { body() }
}
+
+ @Test
+ @RunsInEdt
+ fun testAllowButton() {
+ loginUsersRule.setActiveUser("user2", setOf(loginFeatureRule.FEATURE2))
+ loginUsersRule.setActiveUser("user1", setOf(loginFeatureRule.FEATURE1))
+
+ val component =
+ GoogleLoginApplicationSettingsConfigurableUi()
+ .also { Disposer.register(disposableRule.disposable, it) }
+ .component
+ val list = component.flatten().filterIsInstance<JBList<*>>().single()
+
+ list.setSelectedValue(loginUsersRule.getUser("user2"), false)
+ UIUtil.dispatchAllInvocationEvents()
+
+ val button1 =
+ component
+ .flatten()
+ .single { it.name == "test_feature_1 panel" }
+ .flatten()
+ .filterIsInstance<JButton>()
+ .single()
+ val button2 =
+ component
+ .flatten()
+ .single { it.name == "test_feature_2 panel" }
+ .flatten()
+ .filterIsInstance<JButton>()
+ .single()
+
+ assertThat(button1.isEnabled).isTrue()
+ assertThat(button1.text).isEqualTo("Allow")
+ assertThat(button2.isEnabled).isFalse()
+ assertThat(button2.text).isEqualTo("Allowed")
+
+ list.setSelectedValue(loginUsersRule.getUser("user1"), false)
+ UIUtil.dispatchAllInvocationEvents()
+
+ assertThat(button2.isEnabled).isTrue()
+ assertThat(button2.text).isEqualTo("Allow")
+ assertThat(button1.isEnabled).isFalse()
+ assertThat(button1.text).isEqualTo("Allowed")
+
+ button2.actionListeners.forEach { it.actionPerformed(null) }
+ UIUtil.dispatchAllInvocationEvents()
+ waitForCondition(1.seconds) { !button2.isEnabled }
+ assertThat(button2.text).isEqualTo("Allowed")
+ assertThat(loginUsersRule.getUser("user2")?.isLoggedIn(loginFeatureRule.FEATURE2)).isTrue()
+ }
}