Unified · Split
| @@ -4,8 +4,8 @@ import { useAtomSet, useAtomValue, Result } from "@effect-atom/atom-react"; · 3 unmodified lines | ||
| 4 | 4 | import { connectionsAtom } from "@executor/react/api/atoms"; |
| 5 | 5 | import { useScope } from "@executor/react/api/scope-context"; |
| 6 | 6 | import { connectionWriteKeys, sourceWriteKeys } from "@executor/react/api/reactivity-keys"; |
| 7 | −import { Button } from "@executor/react/components/button"; | |
| 8 | 7 | import { |
| 8 | + OAuthSignInButton, | |
| 9 | 9 | oauthCallbackUrl, |
| 10 | 10 | useOAuthPopupFlow, |
| 11 | 11 | type OAuthCompletionPayload, |
| @@ -96,17 +96,13 @@ export default function GoogleDiscoverySignInButton(props: { sourceId: string }) · 84 unmodified lines | ||
| 96 | 96 | if (!oauth2) return null; |
| 97 | 97 | |
| 98 | 98 | return ( |
| 99 | − <div className="flex items-center gap-2"> | |
| 100 | − {oauth.error && <span className="text-xs text-destructive">{oauth.error}</span>} | |
| 101 | − <Button variant="outline" size="sm" onClick={() => void handleSignIn()} disabled={oauth.busy}> | |
| 102 | − {oauth.busy | |
| 103 | − ? isConnected | |
| 104 | − ? "Reconnecting…" | |
| 105 | − : "Signing in…" | |
| 106 | − : isConnected | |
| 107 | − ? "Reconnect" | |
| 108 | − : "Sign in"} | |
| 109 | − </Button> | |
| 110 | − </div> | |
| 99 | + <OAuthSignInButton | |
| 100 | + busy={oauth.busy} | |
| 101 | + error={oauth.error} | |
| 102 | + isConnected={isConnected} | |
| 103 | + onSignIn={() => void handleSignIn()} | |
| 104 | + reconnectingLabel="Reconnecting…" | |
| 105 | + signingInLabel="Signing in…" | |
| 106 | + /> | |
| 111 | 107 | ); |
| 112 | 108 | } |
| @@ -4,8 +4,8 @@ import { useAtomSet, useAtomValue, Result } from "@effect-atom/atom-react"; · 3 unmodified lines | ||
| 4 | 4 | import { connectionsAtom } from "@executor/react/api/atoms"; |
| 5 | 5 | import { useScope } from "@executor/react/api/scope-context"; |
| 6 | 6 | import { sourceWriteKeys } from "@executor/react/api/reactivity-keys"; |
| 7 | −import { Button } from "@executor/react/components/button"; | |
| 8 | 7 | import { |
| 8 | + OAuthSignInButton, | |
| 9 | 9 | oauthCallbackUrl, |
| 10 | 10 | oauthConnectionId, |
| 11 | 11 | useOAuthPopupFlow, |
| @@ -64,17 +64,11 @@ export default function GraphqlSignInButton(props: { sourceId: string }) { · 52 unmodified lines | ||
| 64 | 64 | if (!oauth2) return null; |
| 65 | 65 | |
| 66 | 66 | return ( |
| 67 | − <div className="flex items-center gap-2"> | |
| 68 | − {oauth.error && <span className="text-xs text-destructive">{oauth.error}</span>} | |
| 69 | − <Button variant="outline" size="sm" onClick={() => void handleSignIn()} disabled={oauth.busy}> | |
| 70 | − {oauth.busy | |
| 71 | − ? isConnected | |
| 72 | − ? "Reconnecting..." | |
| 73 | − : "Signing in..." | |
| 74 | − : isConnected | |
| 75 | − ? "Reconnect" | |
| 76 | − : "Sign in"} | |
| 77 | − </Button> | |
| 78 | − </div> | |
| 67 | + <OAuthSignInButton | |
| 68 | + busy={oauth.busy} | |
| 69 | + error={oauth.error} | |
| 70 | + isConnected={isConnected} | |
| 71 | + onSignIn={() => void handleSignIn()} | |
| 72 | + /> | |
| 79 | 73 | ); |
| 80 | 74 | } |
| @@ -4,8 +4,8 @@ import { useAtomSet, useAtomValue, Result } from "@effect-atom/atom-react"; · 3 unmodified lines | ||
| 4 | 4 | import { useScope } from "@executor/react/api/scope-context"; |
| 5 | 5 | import { sourceWriteKeys } from "@executor/react/api/reactivity-keys"; |
| 6 | 6 | import { connectionsAtom } from "@executor/react/api/atoms"; |
| 7 | −import { Button } from "@executor/react/components/button"; | |
| 8 | 7 | import { |
| 8 | + OAuthSignInButton, | |
| 9 | 9 | oauthCallbackUrl, |
| 10 | 10 | oauthConnectionId, |
| 11 | 11 | useOAuthPopupFlow, |
| @@ -75,17 +75,13 @@ export default function McpSignInButton(props: { sourceId: string }) { · 63 unmodified lines | ||
| 75 | 75 | if (!oauth2) return null; |
| 76 | 76 | |
| 77 | 77 | return ( |
| 78 | − <div className="flex items-center gap-2"> | |
| 79 | − {oauth.error && <span className="text-xs text-destructive">{oauth.error}</span>} | |
| 80 | − <Button variant="outline" size="sm" onClick={() => void handleSignIn()} disabled={oauth.busy}> | |
| 81 | − {oauth.busy | |
| 82 | − ? isConnected | |
| 83 | − ? "Reconnecting…" | |
| 84 | − : "Signing in…" | |
| 85 | − : isConnected | |
| 86 | − ? "Reconnect" | |
| 87 | − : "Sign in"} | |
| 88 | − </Button> | |
| 89 | − </div> | |
| 78 | + <OAuthSignInButton | |
| 79 | + busy={oauth.busy} | |
| 80 | + error={oauth.error} | |
| 81 | + isConnected={isConnected} | |
| 82 | + onSignIn={() => void handleSignIn()} | |
| 83 | + reconnectingLabel="Reconnecting…" | |
| 84 | + signingInLabel="Signing in…" | |
| 85 | + /> | |
| 90 | 86 | ); |
| 91 | 87 | } |
| @@ -4,6 +4,7 @@ import { useAtomSet } from "@effect-atom/atom-react"; · 3 unmodified lines | ||
| 4 | 4 | import { cancelOAuth, startOAuth } from "../api/atoms"; |
| 5 | 5 | import { openOAuthPopup, type OAuthPopupResult } from "../api/oauth-popup"; |
| 6 | 6 | import { useScope } from "../api/scope-context"; |
| 7 | +import { Button } from "../components/button"; | |
| 7 | 8 | import { OAUTH_POPUP_MESSAGE_TYPE, type OAuthStrategy } from "@executor/sdk"; |
| 8 | 9 | |
| 9 | 10 | type SecretBackedValue = |
| @@ -231,3 +232,29 @@ export function useOAuthPopupFlow< · 221 unmodified lines | ||
| 231 | 232 | cancel, |
| 232 | 233 | }; |
| 233 | 234 | } |
| 235 | + | |
| 236 | +export function OAuthSignInButton(props: { | |
| 237 | + readonly busy: boolean; | |
| 238 | + readonly error: string | null; | |
| 239 | + readonly isConnected: boolean; | |
| 240 | + readonly onSignIn: () => void; | |
| 241 | + readonly reconnectingLabel?: string; | |
| 242 | + readonly signingInLabel?: string; | |
| 243 | + readonly reconnectLabel?: string; | |
| 244 | + readonly signInLabel?: string; | |
| 245 | +}) { | |
| 246 | + return ( | |
| 247 | + <div className="flex items-center gap-2"> | |
| 248 | + {props.error && <span className="text-xs text-destructive">{props.error}</span>} | |
| 249 | + <Button variant="outline" size="sm" onClick={props.onSignIn} disabled={props.busy}> | |
| 250 | + {props.busy | |
| 251 | + ? props.isConnected | |
| 252 | + ? (props.reconnectingLabel ?? "Reconnecting...") | |
| 253 | + : (props.signingInLabel ?? "Signing in...") | |
| 254 | + : props.isConnected | |
| 255 | + ? (props.reconnectLabel ?? "Reconnect") | |
| 256 | + : (props.signInLabel ?? "Sign in")} | |
| 257 | + </Button> | |
| 258 | + </div> | |
| 259 | + ); | |
| 260 | +} | |