Skip to content

Commit 8ba895a

Browse files
author
Riajul Islam
committed
fix: show configured sign-in options
1 parent 8f783c0 commit 8ba895a

2 files changed

Lines changed: 318 additions & 0 deletions

File tree

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
diff --git a/packages/remote-web/src/pages/InvitationPage.tsx b/packages/remote-web/src/pages/InvitationPage.tsx
2+
index ae9b23f1c..466e42741 100644
3+
--- a/packages/remote-web/src/pages/InvitationPage.tsx
4+
+++ b/packages/remote-web/src/pages/InvitationPage.tsx
5+
@@ -1,11 +1,13 @@
6+
import { useEffect, useState } from "react";
7+
import { useParams } from "@tanstack/react-router";
8+
import {
9+
+ getAuthMethods,
10+
getInvitation,
11+
initOAuth,
12+
type InvitationLookupResponse,
13+
type OAuthProvider,
14+
} from "@remote/shared/lib/api";
15+
+import { useQuery } from "@tanstack/react-query";
16+
import {
17+
generateChallenge,
18+
generateVerifier,
19+
@@ -22,6 +24,18 @@ export default function InvitationPage() {
20+
const [pendingProvider, setPendingProvider] = useState<OAuthProvider | null>(
21+
null,
22+
);
23+
+ const {
24+
+ data: authMethods,
25+
+ error: authMethodsError,
26+
+ isError: isAuthMethodsError,
27+
+ } = useQuery({
28+
+ queryKey: ["remote-auth-methods"],
29+
+ queryFn: getAuthMethods,
30+
+ staleTime: 60_000,
31+
+ });
32+
+ const oauthProviders = (authMethods?.oauth_providers ?? []).filter(
33+
+ isSupportedOAuthProvider,
34+
+ );
35+
36+
useEffect(() => {
37+
let cancelled = false;
38+
@@ -129,24 +143,30 @@ export default function InvitationPage() {
39+
<p className="text-sm text-high">{error}</p>
40+
</div>
41+
)}
42+
+ {isAuthMethodsError && (
43+
+ <div className="rounded-sm border border-error/30 bg-error/10 p-base">
44+
+ <p className="text-sm text-high">
45+
+ {authMethodsError instanceof Error
46+
+ ? authMethodsError.message
47+
+ : "Failed to load available sign-in methods."}
48+
+ </p>
49+
+ </div>
50+
+ )}
51+
52+
<section className="space-y-base border-t border-border pt-base text-center">
53+
<p className="text-sm text-low">Choose a provider to continue:</p>
54+
<div className="flex flex-col items-center gap-2">
55+
- <OAuthButton
56+
- provider="github"
57+
- label="Continue with GitHub"
58+
- onClick={() => void handleOAuthLogin("github")}
59+
- disabled={pendingProvider !== null}
60+
- loading={pendingProvider === "github"}
61+
- />
62+
- <OAuthButton
63+
- provider="google"
64+
- label="Continue with Google"
65+
- onClick={() => void handleOAuthLogin("google")}
66+
- disabled={pendingProvider !== null}
67+
- loading={pendingProvider === "google"}
68+
- />
69+
+ {!isAuthMethodsError &&
70+
+ oauthProviders.map((provider) => (
71+
+ <OAuthButton
72+
+ key={provider}
73+
+ provider={provider}
74+
+ label={`Continue with ${providerLabel(provider)}`}
75+
+ onClick={() => void handleOAuthLogin(provider)}
76+
+ disabled={pendingProvider !== null}
77+
+ loading={pendingProvider === provider}
78+
+ />
79+
+ ))}
80+
</div>
81+
</section>
82+
</div>
83+
@@ -155,6 +175,23 @@ export default function InvitationPage() {
84+
);
85+
}
86+
87+
+const SUPPORTED_OAUTH_PROVIDERS: OAuthProvider[] = ["github", "google", "zoho"];
88+
+
89+
+function isSupportedOAuthProvider(provider: string): provider is OAuthProvider {
90+
+ return SUPPORTED_OAUTH_PROVIDERS.includes(provider as OAuthProvider);
91+
+}
92+
+
93+
+function providerLabel(provider: OAuthProvider): string {
94+
+ switch (provider) {
95+
+ case "github":
96+
+ return "GitHub";
97+
+ case "google":
98+
+ return "Google";
99+
+ case "zoho":
100+
+ return "Zoho";
101+
+ }
102+
+}
103+
+
104+
function OAuthButton({
105+
provider,
106+
label,
107+
@@ -176,9 +213,7 @@ function OAuthButton({
108+
onClick={onClick}
109+
disabled={disabled || loading}
110+
>
111+
- {loading
112+
- ? `Opening ${provider === "github" ? "GitHub" : "Google"}...`
113+
- : label}
114+
+ {loading ? `Opening ${providerLabel(provider)}...` : label}
115+
</button>
116+
);
117+
}
118+
diff --git a/packages/remote-web/src/pages/LoginPage.tsx b/packages/remote-web/src/pages/LoginPage.tsx
119+
index 9446e0ed0..b9369efda 100644
120+
--- a/packages/remote-web/src/pages/LoginPage.tsx
121+
+++ b/packages/remote-web/src/pages/LoginPage.tsx
122+
@@ -34,7 +34,9 @@ export default function LoginPage() {
123+
});
124+
125+
const hasLocalAuth = authMethods?.local_auth_enabled ?? false;
126+
- const oauthProviders = authMethods?.oauth_providers ?? [];
127+
+ const oauthProviders = (authMethods?.oauth_providers ?? []).filter(
128+
+ isSupportedOAuthProvider,
129+
+ );
130+
const hasOAuthProviders = oauthProviders.length > 0;
131+
132+
const handleLogin = async (provider: OAuthProvider) => {
133+
@@ -152,27 +154,16 @@ export default function LoginPage() {
134+
135+
<div className="flex flex-col items-center gap-2">
136+
{!isAuthMethodsError &&
137+
- hasOAuthProviders &&
138+
- oauthProviders.includes("github") && (
139+
- <OAuthButton
140+
- provider="github"
141+
- label="Continue with GitHub"
142+
- onClick={() => void handleLogin("github")}
143+
- disabled={pending !== null}
144+
- loading={pending === "github"}
145+
- />
146+
- )}
147+
- {!isAuthMethodsError &&
148+
- hasOAuthProviders &&
149+
- oauthProviders.includes("google") && (
150+
+ oauthProviders.map((provider) => (
151+
<OAuthButton
152+
- provider="google"
153+
- label="Continue with Google"
154+
- onClick={() => void handleLogin("google")}
155+
+ key={provider}
156+
+ provider={provider}
157+
+ label={`Continue with ${providerLabel(provider)}`}
158+
+ onClick={() => void handleLogin(provider)}
159+
disabled={pending !== null}
160+
- loading={pending === "google"}
161+
+ loading={pending === provider}
162+
/>
163+
- )}
164+
+ ))}
165+
</div>
166+
</section>
167+
168+
@@ -193,6 +184,23 @@ export default function LoginPage() {
169+
);
170+
}
171+
172+
+const SUPPORTED_OAUTH_PROVIDERS: OAuthProvider[] = ["github", "google", "zoho"];
173+
+
174+
+function isSupportedOAuthProvider(provider: string): provider is OAuthProvider {
175+
+ return SUPPORTED_OAUTH_PROVIDERS.includes(provider as OAuthProvider);
176+
+}
177+
+
178+
+function providerLabel(provider: OAuthProvider): string {
179+
+ switch (provider) {
180+
+ case "github":
181+
+ return "GitHub";
182+
+ case "google":
183+
+ return "Google";
184+
+ case "zoho":
185+
+ return "Zoho";
186+
+ }
187+
+}
188+
+
189+
function OAuthButton({
190+
provider,
191+
label,
192+
@@ -214,9 +222,7 @@ function OAuthButton({
193+
onClick={onClick}
194+
disabled={disabled || loading}
195+
>
196+
- {loading
197+
- ? `Opening ${provider === "github" ? "GitHub" : "Google"}...`
198+
- : label}
199+
+ {loading ? `Opening ${providerLabel(provider)}...` : label}
200+
</button>
201+
);
202+
}
203+
diff --git a/packages/remote-web/src/shared/lib/api.ts b/packages/remote-web/src/shared/lib/api.ts
204+
index feebf0cb4..f8910a66c 100644
205+
--- a/packages/remote-web/src/shared/lib/api.ts
206+
+++ b/packages/remote-web/src/shared/lib/api.ts
207+
@@ -5,7 +5,7 @@ import type { ListOrganizationsResponse } from "shared/types";
208+
209+
const API_BASE = import.meta.env.VITE_API_BASE_URL || "";
210+
211+
-export type OAuthProvider = "github" | "google";
212+
+export type OAuthProvider = "github" | "google" | "zoho";
213+
214+
export type AuthMethodsResponse = {
215+
local_auth_enabled: boolean;
216+
diff --git a/packages/web-core/src/features/onboarding/ui/OnboardingSignInPage.tsx b/packages/web-core/src/features/onboarding/ui/OnboardingSignInPage.tsx
217+
index 3e9b5fd70..8c4454228 100644
218+
--- a/packages/web-core/src/features/onboarding/ui/OnboardingSignInPage.tsx
219+
+++ b/packages/web-core/src/features/onboarding/ui/OnboardingSignInPage.tsx
220+
@@ -61,7 +61,22 @@ type SignInCompletionMethod =
221+
| 'auth_dialog'
222+
| 'local_auth'
223+
| 'oauth_github'
224+
- | 'oauth_google';
225+
+ | 'oauth_google'
226+
+ | 'oauth_zoho';
227+
+
228+
+function completionMethodForProvider(
229+
+ provider: OAuthProvider
230+
+): SignInCompletionMethod {
231+
+ switch (provider) {
232+
+ case 'github':
233+
+ return 'oauth_github';
234+
+ case 'google':
235+
+ return 'oauth_google';
236+
+ case 'zoho':
237+
+ return 'oauth_zoho';
238+
+ }
239+
+}
240+
+
241+
function resolveTheme(theme: ThemeMode): 'light' | 'dark' {
242+
if (theme === ThemeMode.SYSTEM) {
243+
return window.matchMedia('(prefers-color-scheme: dark)').matches
244+
@@ -98,8 +113,9 @@ export function OnboardingSignInPage() {
245+
staleTime: 60_000,
246+
});
247+
const hasLocalAuth = authMethods?.local_auth_enabled ?? false;
248+
- const oauthProviders = authMethods?.oauth_providers ?? [];
249+
- const hasOAuthProviders = oauthProviders.length > 0;
250+
+ const oauthProviders = (authMethods?.oauth_providers ?? []).filter(
251+
+ isSupportedOAuthProvider
252+
+ );
253+
254+
const trackRemoteOnboardingEvent = useCallback(
255+
(eventName: string, properties: Record<string, unknown> = {}) => {
256+
@@ -226,7 +242,7 @@ export function OnboardingSignInPage() {
257+
258+
if (didSignIn) {
259+
await finishOnboarding({
260+
- method: provider === 'github' ? 'oauth_github' : 'oauth_google',
261+
+ method: completionMethodForProvider(provider),
262+
});
263+
}
264+
};
265+
@@ -332,24 +348,16 @@ export function OnboardingSignInPage() {
266+
/>
267+
) : !isAuthMethodsError ? (
268+
<>
269+
- {hasOAuthProviders && oauthProviders.includes('github') && (
270+
- <OAuthSignInButton
271+
- provider="github"
272+
- onClick={() => void handleProviderSignIn('github')}
273+
- disabled={saving || pendingProvider !== null}
274+
- loading={pendingProvider === 'github'}
275+
- loadingText="Opening GitHub..."
276+
- />
277+
- )}
278+
- {hasOAuthProviders && oauthProviders.includes('google') && (
279+
+ {oauthProviders.map((provider) => (
280+
<OAuthSignInButton
281+
- provider="google"
282+
- onClick={() => void handleProviderSignIn('google')}
283+
+ key={provider}
284+
+ provider={provider}
285+
+ onClick={() => void handleProviderSignIn(provider)}
286+
disabled={saving || pendingProvider !== null}
287+
- loading={pendingProvider === 'google'}
288+
- loadingText="Opening Google..."
289+
+ loading={pendingProvider === provider}
290+
+ loadingText={`Opening ${providerLabel(provider)}...`}
291+
/>
292+
- )}
293+
+ ))}
294+
</>
295+
) : null}
296+
</section>
297+
@@ -475,3 +483,20 @@ export function OnboardingSignInPage() {
298+
</div>
299+
);
300+
}
301+
+
302+
+const SUPPORTED_OAUTH_PROVIDERS: OAuthProvider[] = ['github', 'google', 'zoho'];
303+
+
304+
+function isSupportedOAuthProvider(provider: string): provider is OAuthProvider {
305+
+ return SUPPORTED_OAUTH_PROVIDERS.includes(provider as OAuthProvider);
306+
+}
307+
+
308+
+function providerLabel(provider: OAuthProvider): string {
309+
+ switch (provider) {
310+
+ case 'github':
311+
+ return 'GitHub';
312+
+ case 'google':
313+
+ return 'Google';
314+
+ case 'zoho':
315+
+ return 'Zoho';
316+
+ }
317+
+}

patches/series

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@
1818
0017-fix-add-30s-WebSocket-ping-keepalive.patch
1919
0018-feat-allowed-email-domains-restriction.patch
2020
0019-feat-add-browser-notification-support.patch
21+
0020-fix-show-configured-sign-in-options.patch

0 commit comments

Comments
 (0)