Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| 'use client'; | |
| import { useEffect, useMemo, useState } from 'react'; | |
| import JobsTable from '@/components/JobsTable'; | |
| import { TopBar, MainContent } from '@/components/layout'; | |
| import Link from 'next/link'; | |
| import { useAuth } from '@/contexts/AuthContext'; | |
| import HFLoginButton from '@/components/HFLoginButton'; | |
| import useSettings from '@/hooks/useSettings'; | |
| import { apiClient } from '@/utils/api'; | |
| export default function Dashboard() { | |
| const { status: authStatus, namespace, token: authToken } = useAuth(); | |
| const { settings } = useSettings(); | |
| const isAuthenticated = authStatus === 'authenticated'; | |
| const effectiveToken = useMemo(() => authToken || settings.HF_TOKEN, [authToken, settings.HF_TOKEN]); | |
| type OrgStatus = 'idle' | 'checking' | 'member' | 'missing' | 'error'; | |
| const [orgStatus, setOrgStatus] = useState<OrgStatus>('idle'); | |
| useEffect(() => { | |
| if (!isAuthenticated) { | |
| setOrgStatus('idle'); | |
| return; | |
| } | |
| if (!effectiveToken) { | |
| setOrgStatus('idle'); | |
| return; | |
| } | |
| let cancelled = false; | |
| setOrgStatus('checking'); | |
| apiClient | |
| .post('/api/hf-hub', { | |
| action: 'whoami', | |
| token: effectiveToken, | |
| }) | |
| .then(response => { | |
| if (cancelled) return; | |
| const orgsRaw = response.data?.user?.orgs ?? response.data?.user?.organizations ?? []; | |
| const REQUIRED_ORG = 'lora-training-frenzi'; | |
| const isMember = Array.isArray(orgsRaw) | |
| ? orgsRaw.some((org: any) => { | |
| if (!org) return false; | |
| if (typeof org === 'string') { | |
| return org === REQUIRED_ORG; | |
| } | |
| const nameMatch = org?.name || org?.organization || org?.namespace || org?.id; | |
| return nameMatch === REQUIRED_ORG; | |
| }) | |
| : false; | |
| setOrgStatus(isMember ? 'member' : 'missing'); | |
| }) | |
| .catch(() => { | |
| if (!cancelled) { | |
| setOrgStatus('error'); | |
| } | |
| }); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [effectiveToken, isAuthenticated]); | |
| return ( | |
| <> | |
| <TopBar> | |
| <div> | |
| <h1 className="text-lg">Dashboard</h1> | |
| </div> | |
| <div className="flex-1" /> | |
| </TopBar> | |
| <MainContent> | |
| <div className="border border-gray-800 rounded-xl bg-gray-900 p-6 flex flex-col gap-4"> | |
| <div> | |
| <h2 className="text-xl font-semibold text-gray-100"> | |
| {isAuthenticated ? `Welcome back, ${namespace || 'creator'}!` : 'Welcome to Ostris AI Toolkit'} | |
| </h2> | |
| <p className="text-sm text-gray-400 mt-2"> | |
| {isAuthenticated | |
| ? 'You are signed in with Hugging Face and can manage jobs, datasets, and submissions. Train LoRAs at $0.042/minute if you are a PRO user.' | |
| : 'Authenticate with Hugging Face or add a personal access token to create jobs, upload datasets, and launch training. Train LoRAs at $0.042/minute if you are a PRO user.'} | |
| {!isAuthenticated && ( | |
| <> | |
| {' '} | |
| <a | |
| href="https://huggingface.co/subscribe/pro" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="text-blue-400 underline hover:text-blue-300" | |
| > | |
| Subscribe to PRO | |
| </a> | |
| </> | |
| )} | |
| </p> | |
| </div> | |
| {isAuthenticated ? ( | |
| <div className="flex flex-col gap-4 text-sm"> | |
| <div className="flex flex-wrap items-center gap-3"> | |
| <Link | |
| href="/jobs/new" | |
| className="px-4 py-2 rounded-md bg-blue-600 hover:bg-blue-500 text-white transition-colors" | |
| > | |
| Create a Training Job | |
| </Link> | |
| <Link | |
| href="/datasets" | |
| className="px-4 py-2 rounded-md bg-gray-800 hover:bg-gray-700 text-gray-200 transition-colors" | |
| > | |
| Manage Datasets | |
| </Link> | |
| <Link | |
| href="/settings" | |
| className="px-4 py-2 rounded-md border border-gray-700 text-gray-300 hover:border-gray-600 transition-colors" | |
| > | |
| Settings | |
| </Link> | |
| </div> | |
| </div> | |
| ) : ( | |
| <div className="flex flex-col gap-4 text-sm text-gray-300"> | |
| <div> | |
| <HFLoginButton size="md" /> | |
| </div> | |
| <Link | |
| href="/settings" | |
| className="text-xs text-blue-400 hover:text-blue-300" | |
| > | |
| Or manage tokens in Settings | |
| </Link> | |
| </div> | |
| )} | |
| </div> | |
| <div className="w-full mt-6"> | |
| <div className="flex justify-between items-center mb-2"> | |
| <h1 className="text-md">Active Jobs</h1> | |
| <div className="text-xs text-gray-500"> | |
| <Link href="/jobs">View All</Link> | |
| </div> | |
| </div> | |
| {isAuthenticated ? ( | |
| <JobsTable onlyActive /> | |
| ) : ( | |
| <div className="border border-gray-800 rounded-lg p-6 bg-gray-900 text-gray-400 text-sm"> | |
| Sign in with Hugging Face or add an access token in Settings to view and manage jobs. | |
| </div> | |
| )} | |
| </div> | |
| </MainContent> | |
| </> | |
| ); | |
| } | |