Skip to content

Commit d8df88b

Browse files
authored
Share OAuth sign-in button UI (#451)
1 parent 9638cc3 commit d8df88b

4 files changed

Lines changed: 52 additions & 39 deletions

File tree

‎packages/plugins/google-discovery/src/react/GoogleDiscoverySignInButton.tsx‎

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { useAtomSet, useAtomValue, Result } from "@effect-atom/atom-react";
44
import { connectionsAtom } from "@executor/react/api/atoms";
55
import { useScope } from "@executor/react/api/scope-context";
66
import { connectionWriteKeys, sourceWriteKeys } from "@executor/react/api/reactivity-keys";
7-
import { Button } from "@executor/react/components/button";
87
import {
8+
OAuthSignInButton,
99
oauthCallbackUrl,
1010
useOAuthPopupFlow,
1111
type OAuthCompletionPayload,
@@ -96,17 +96,13 @@ export default function GoogleDiscoverySignInButton(props: { sourceId: string })
9696
if (!oauth2) return null;
9797

9898
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+
/>
111107
);
112108
}

‎packages/plugins/graphql/src/react/GraphqlSignInButton.tsx‎

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { useAtomSet, useAtomValue, Result } from "@effect-atom/atom-react";
44
import { connectionsAtom } from "@executor/react/api/atoms";
55
import { useScope } from "@executor/react/api/scope-context";
66
import { sourceWriteKeys } from "@executor/react/api/reactivity-keys";
7-
import { Button } from "@executor/react/components/button";
87
import {
8+
OAuthSignInButton,
99
oauthCallbackUrl,
1010
oauthConnectionId,
1111
useOAuthPopupFlow,
@@ -64,17 +64,11 @@ export default function GraphqlSignInButton(props: { sourceId: string }) {
6464
if (!oauth2) return null;
6565

6666
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+
/>
7973
);
8074
}

‎packages/plugins/mcp/src/react/McpSignInButton.tsx‎

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { useAtomSet, useAtomValue, Result } from "@effect-atom/atom-react";
44
import { useScope } from "@executor/react/api/scope-context";
55
import { sourceWriteKeys } from "@executor/react/api/reactivity-keys";
66
import { connectionsAtom } from "@executor/react/api/atoms";
7-
import { Button } from "@executor/react/components/button";
87
import {
8+
OAuthSignInButton,
99
oauthCallbackUrl,
1010
oauthConnectionId,
1111
useOAuthPopupFlow,
@@ -75,17 +75,13 @@ export default function McpSignInButton(props: { sourceId: string }) {
7575
if (!oauth2) return null;
7676

7777
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+
/>
9086
);
9187
}

‎packages/react/src/plugins/oauth-sign-in.tsx‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useAtomSet } from "@effect-atom/atom-react";
44
import { cancelOAuth, startOAuth } from "../api/atoms";
55
import { openOAuthPopup, type OAuthPopupResult } from "../api/oauth-popup";
66
import { useScope } from "../api/scope-context";
7+
import { Button } from "../components/button";
78
import { OAUTH_POPUP_MESSAGE_TYPE, type OAuthStrategy } from "@executor/sdk";
89

910
type SecretBackedValue =
@@ -231,3 +232,29 @@ export function useOAuthPopupFlow<
231232
cancel,
232233
};
233234
}
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+
}

0 commit comments

Comments
 (0)