import { useEffect, useState } from "react"; import { BrowserRouter, Routes, Route, Navigate, useLocation, useNavigate, } from "react-router-dom"; import { useAppStore } from "./stores/useAppStore"; import { NavBar } from "./components/molecules"; import { LoginPage, MonitoringPage, ProfilesPage, SettingsPage } from "./pages"; import * as api from "./services/api"; import { AUTH_REQUIRED_EVENT, clearStoredAuthToken, getStoredAuthToken, setStoredAuthToken, } from "./services/auth"; type AuthMode = "probing" | "required" | "open" | "unreachable"; const AUTH_RETRY_DELAYS_MS = [1000, 2000, 4000, 8000, 15000] as const; function AppContent() { const { setInstances, setProfiles, setAgents, setServerInfo, applyMonitoringSnapshot, settings, } = useAppStore(); const location = useLocation(); const navigate = useNavigate(); const memoryMetricsEnabled = settings.monitoring?.memoryMetrics ?? false; // Auto-login from ?token= query parameter (e.g. from wizard URL) // or injected meta tag for Hugging Face Spaces integration useEffect(() => { const params = new URLSearchParams(window.location.search); let urlToken = params.get("token"); if (!urlToken) { const meta = document.querySelector("meta[name='pinchtab-token']"); const metaContent = meta?.getAttribute("content") || ""; // Exclude the unreplaced template literal from injection if (metaContent && metaContent !== "{{PINCHTAB_TOKEN_INJECT}}") { urlToken = metaContent; } } if (urlToken) { setStoredAuthToken(urlToken); const clean = new URL(window.location.href); clean.searchParams.delete("token"); window.history.replaceState({}, "", clean.pathname + clean.hash); // Let the main login flow handle reload if necessary, but actually // if we just updated localStorage we want to reload so state is updated if (getStoredAuthToken() !== urlToken) { window.location.reload(); } } }, []); const authToken = getStoredAuthToken(); const hasStoredToken = authToken !== ""; const [authMode, setAuthMode] = useState( hasStoredToken ? "required" : "probing", ); const [authRetryCount, setAuthRetryCount] = useState(0); const dashboardAccessible = hasStoredToken || authMode === "open"; const loginRequired = !hasStoredToken && authMode === "required"; useEffect(() => { document.documentElement.setAttribute("data-site-mode", "agent"); }, []); useEffect(() => { if (hasStoredToken) { setAuthMode("required"); setAuthRetryCount(0); return; } if (authMode === "open" || authMode === "unreachable") { return; } let cancelled = false; api .probeBackendAuth() .then((result) => { if (cancelled) { return; } setAuthMode(result.requiresAuth ? "required" : "open"); setAuthRetryCount(0); if (result.health) { setServerInfo(result.health); } }) .catch((error) => { if (cancelled) { return; } console.error("Failed to probe backend auth", error); setAuthMode("unreachable"); }); return () => { cancelled = true; }; }, [authMode, hasStoredToken, setServerInfo]); useEffect(() => { if ( hasStoredToken || authMode !== "unreachable" || authRetryCount >= AUTH_RETRY_DELAYS_MS.length ) { return; } const timer = window.setTimeout(() => { setAuthRetryCount((count) => count + 1); setAuthMode("probing"); }, AUTH_RETRY_DELAYS_MS[authRetryCount]); return () => { window.clearTimeout(timer); }; }, [authMode, authRetryCount, hasStoredToken]); useEffect(() => { const handleAuthRequired = () => { clearStoredAuthToken(); setAuthMode("required"); setAuthRetryCount(0); navigate("/login", { replace: true, state: { from: location.pathname }, }); }; window.addEventListener(AUTH_REQUIRED_EVENT, handleAuthRequired); return () => window.removeEventListener(AUTH_REQUIRED_EVENT, handleAuthRequired); }, [location.pathname, navigate]); useEffect(() => { if (loginRequired && location.pathname !== "/login") { navigate("/login", { replace: true, state: { from: location.pathname }, }); } }, [location.pathname, loginRequired, navigate]); // Initial load useEffect(() => { if (!dashboardAccessible) { return; } const load = async () => { try { const [instances, profiles, health] = await Promise.all([ api.fetchInstances(), api.fetchProfiles(), api.fetchHealth(), ]); setInstances(instances); setProfiles(profiles); setServerInfo(health); } catch (e) { console.error("Failed to load initial data", e); } }; load(); }, [dashboardAccessible, setInstances, setProfiles, setServerInfo]); // Subscribe to SSE events useEffect(() => { if (!dashboardAccessible) { return; } const unsubscribe = api.subscribeToEvents( { onInit: (agents) => { setAgents(agents); }, onSystem: (event) => { console.log("System event:", event); }, onAgent: (event) => { console.log("Agent event:", event); }, onMonitoring: (snapshot) => { applyMonitoringSnapshot(snapshot, memoryMetricsEnabled); }, }, { includeMemory: memoryMetricsEnabled, }, ); return unsubscribe; }, [ dashboardAccessible, applyMonitoringSnapshot, memoryMetricsEnabled, setAgents, setInstances, setProfiles, ]); if (!hasStoredToken && authMode === "probing") { return (
Checking server authentication...
); } if (!hasStoredToken && authMode === "unreachable") { const nextRetryDelay = authRetryCount < AUTH_RETRY_DELAYS_MS.length ? AUTH_RETRY_DELAYS_MS[authRetryCount] : null; return (
PinchTab is restarting or unreachable. {nextRetryDelay !== null ? ` Retrying in ${Math.ceil(nextRetryDelay / 1000)}s...` : " Automatic retries stopped."}
{nextRetryDelay === null && (
)}
); } if (loginRequired) { return ( } /> } /> ); } return (
} /> } /> } /> } /> } /> } /> } /> } />
); } export default function App() { return ( ); }