This commit is contained in:
ahmed20005 2025-05-27 15:16:48 +03:00 committed by GitHub
commit df78aa0f34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 33619 additions and 1 deletions

View File

@ -44,11 +44,26 @@ export function SupabaseChatAlert({ alert, clearAlert, postMessage }: Props) {
setIsExecuting(true);
try {
// Use authenticated user's access token if available
let accessToken = connection.token;
if (connection.credentials?.supabaseUrl && connection.credentials?.anonKey) {
try {
const { getSupabaseClient } = require("~/lib/supabaseClient");
const supabase = getSupabaseClient(connection.credentials.supabaseUrl, connection.credentials.anonKey);
const session = await supabase.auth.getSession();
if (session.data?.session?.access_token) {
accessToken = session.data.session.access_token;
}
} catch (e) {
// fallback to connection.token
}
}
const response = await fetch('/api/supabase/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${connection.token}`,
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
projectId: connection.selectedProjectId,

View File

@ -0,0 +1,136 @@
import React, { useState } from "react";
import { getSupabaseClient } from "~/lib/supabaseClient";
interface SupabaseAuthProps {
supabaseUrl: string;
supabaseAnonKey: string;
}
export const SupabaseAuth: React.FC<SupabaseAuthProps> = ({
supabaseUrl,
supabaseAnonKey,
}) => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [authState, setAuthState] = useState<"idle" | "loading" | "signedIn" | "signedOut" | "needsConfirmation" | "error">("idle");
const [error, setError] = useState<string | null>(null);
const [user, setUser] = useState<any>(null);
const supabase = getSupabaseClient(supabaseUrl, supabaseAnonKey);
const handleSignUp = async (e: React.FormEvent) => {
e.preventDefault();
setAuthState("loading");
setError(null);
const { data, error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
setAuthState("error");
setError(error.message);
} else if (data.user && !data.user.confirmed_at) {
setAuthState("needsConfirmation");
setUser(data.user);
} else if (data.user) {
setAuthState("signedIn");
setUser(data.user);
}
};
const handleSignIn = async (e: React.FormEvent) => {
e.preventDefault();
setAuthState("loading");
setError(null);
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
setAuthState("error");
setError(error.message);
} else if (data.user) {
setAuthState("signedIn");
setUser(data.user);
}
};
const handleSignOut = async () => {
setAuthState("loading");
setError(null);
const { error } = await supabase.auth.signOut();
if (error) {
setAuthState("error");
setError(error.message);
} else {
setAuthState("signedOut");
setUser(null);
}
};
const handleResendConfirmation = async () => {
setAuthState("loading");
setError(null);
const { error } = await supabase.auth.resend({
type: "signup",
email,
} as any);
if (error) {
setAuthState("error");
setError(error.message);
} else {
setAuthState("needsConfirmation");
}
};
return (
<div className="supabase-auth">
{authState === "signedIn" && user ? (
<div>
<p>Signed in as {user.email}</p>
<button onClick={handleSignOut}>Sign Out</button>
</div>
) : (
<form onSubmit={authState === "needsConfirmation" ? undefined : handleSignIn}>
<input
type="email"
placeholder="Email"
value={email}
onChange={e => setEmail(e.target.value)}
required
autoComplete="email"
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={e => setPassword(e.target.value)}
required
autoComplete="current-password"
/>
<div style={{ display: "flex", gap: "8px" }}>
<button type="button" onClick={handleSignUp} disabled={authState === "loading"}>
Sign Up
</button>
<button type="submit" disabled={authState === "loading"}>
Sign In
</button>
</div>
</form>
)}
{authState === "needsConfirmation" && (
<div>
<p>
Please check your email to confirm your account. After confirming, you can sign in.
</p>
<button onClick={handleResendConfirmation} disabled={authState === "loading"}>
Resend Confirmation Email
</button>
</div>
)}
{error && <div style={{ color: "red" }}>{error}</div>}
</div>
);
};
export default SupabaseAuth;

View File

@ -288,6 +288,19 @@ export function SupabaseConnection() {
)}
</>
)}
{/* Supabase Auth UI */}
{supabaseConn.credentials?.supabaseUrl && supabaseConn.credentials?.anonKey && (
<div className="mt-6">
{/* Dynamically import to avoid SSR issues if needed */}
{typeof window !== "undefined" && (
<>{require("./SupabaseAuth").SupabaseAuth({
supabaseUrl: supabaseConn.credentials.supabaseUrl,
supabaseAnonKey: supabaseConn.credentials.anonKey,
})}</>
)}
</div>
)}
</div>
)}

14
app/lib/supabaseClient.ts Normal file
View File

@ -0,0 +1,14 @@
import { createClient, SupabaseClient } from '@supabase/supabase-js';
let supabase: SupabaseClient | null = null;
let lastUrl: string | null = null;
let lastAnonKey: string | null = null;
export function getSupabaseClient(supabaseUrl: string, supabaseAnonKey: string): SupabaseClient {
if (!supabase || lastUrl !== supabaseUrl || lastAnonKey !== supabaseAnonKey) {
supabase = createClient(supabaseUrl, supabaseAnonKey);
lastUrl = supabaseUrl;
lastAnonKey = supabaseAnonKey;
}
return supabase;
}

33439
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -93,6 +93,7 @@
"@remix-run/cloudflare-pages": "^2.15.2",
"@remix-run/node": "^2.15.2",
"@remix-run/react": "^2.15.2",
"@supabase/supabase-js": "^2.49.4",
"@tanstack/react-virtual": "^3.13.0",
"@types/react-beautiful-dnd": "^13.1.8",
"@uiw/codemirror-theme-vscode": "^4.23.6",