// GitHub + HF connection status + OAuth trigger. Shows connection status or // a "Connect" button. Handles 401 (session expired) by prompting reconnect. import { useEffect, useMemo, useState } from "react"; import { GitHubClient, type GithubStatus } from "../api/github"; import { ApiError, type Settings } from "../api/panel"; import { getJWTSub } from "../lib/jwt"; interface Props { settings: Settings; onConnected?: (sessionId: string, username: string) => void; } export function GithubConnect({ settings, onConnected }: Props) { const [status, setStatus] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [sessionExpired, setSessionExpired] = useState(false); const client = useMemo(() => new GitHubClient(settings), [settings]); const hasSession = !!settings.githubSessionId; useEffect(() => { if (!settings.githubSessionId) { setLoading(false); return; } setSessionExpired(false); let alive = true; client .status() .then((s) => { if (alive) setStatus(s); }) .catch((e) => { if (alive) { if (e instanceof ApiError && e.status === 401) { setSessionExpired(true); } else { setError("Failed to check connection status"); } } }) .finally(() => { if (alive) setLoading(false); }); return () => { alive = false; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [settings.githubSessionId]); function handleConnect() { // OAuth proxy flow: redirect to the main Space's login endpoint which handles // the GitHub OAuth and forwards the callback back to this user's Space. // If user already has a session (e.g. from HF OAuth), pass its `sub` so // the backend merges the GitHub account instead of creating a new one. const MAIN_SPACE = "https://scoobybaby1999-loom.hf.space"; const thisSpace = window.location.origin; const existingId = settings.githubSessionId ? getJWTSub(settings.githubSessionId) : null; const existingParam = existingId ? `&existing_id=${encodeURIComponent(existingId)}` : ""; const loginUrl = `${MAIN_SPACE}/api/auth/github/login?redirect_to=${encodeURIComponent(thisSpace)}${existingParam}`; window.location.href = loginUrl; } async function handleDisconnect() { try { await client.disconnect(); onConnected?.("", ""); setStatus(null); } catch { setError("Failed to disconnect"); } } if (loading) { return ( checking connection… ); } if (sessionExpired) { return (
session expired
); } if (error) { return ( {error} ); } // If they have a GitHub connection, show fully connected if (hasSession && status?.github_username) { return (
{status.github_username} {status.hf_username && ( · HF: {status.hf_username} )}
); } // If they have any session (HF only) they need to connect GitHub return ( ); }