diff options
author | Joe Baker-Malone <jbakermalone@google.com> | 2023-12-27 12:42:17 -0800 |
---|---|---|
committer | Joe Baker-Malone <jbakermalone@google.com> | 2024-02-01 16:13:54 -0800 |
commit | 3e8b82d991ef81c666ef0666f321f9c63e3f6474 (patch) | |
tree | e996aa7d5574c81c07ca3e398410549ef807db13 | |
parent | fdba33c5e06dbb1a6b266f7e12d52dc2144f0802 (diff) | |
download | tools-3e8b82d991ef81c666ef0666f321f9c63e3f6474.tar.gz |
Implement login button
Test: added
Bug: 308497310
Change-Id: Ieedc33864f5ec3eae4c2331e0eaee7293d3e7691
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() + } } |