Spaces:
Sleeping
Sleeping
| import { useState } from "react"; | |
| import { FlaskConical, Orbit, ShieldCheck } from "lucide-react"; | |
| import { createProjectAndRun, RankedCandidate } from "./api"; | |
| import { ProjectForm } from "./components/ProjectForm"; | |
| import { PipelineSteps } from "./components/PipelineSteps"; | |
| import { CandidateTable } from "./components/CandidateTable"; | |
| import { CandidateDetail } from "./components/CandidateDetail"; | |
| import "./styles.css"; | |
| export default function App() { | |
| const [status, setStatus] = useState("idle"); | |
| const [error, setError] = useState<string | null>(null); | |
| const [candidates, setCandidates] = useState<RankedCandidate[]>([]); | |
| const selectedCandidate = candidates[0] ?? null; | |
| async function run(payload: Record<string, string>) { | |
| setStatus("running"); | |
| setError(null); | |
| try { | |
| const result = await createProjectAndRun(payload); | |
| setStatus(result.status); | |
| setError(result.error); | |
| setCandidates(result.ranked_candidates ?? []); | |
| } catch (err) { | |
| setStatus("failed"); | |
| setError(err instanceof Error ? err.message : "Pipeline failed"); | |
| } | |
| } | |
| return ( | |
| <main className="app-shell"> | |
| <header className="topbar"> | |
| <div className="brand-block"> | |
| <div className="brand"> | |
| <span className="brand-mark"> | |
| <FlaskConical size={23} /> | |
| </span> | |
| <span>Fast Follow Structure Generator</span> | |
| </div> | |
| <p>AI-assisted molecular optimization workbench for fast-follow discovery.</p> | |
| </div> | |
| <div className="topbar-signals" aria-label="Workbench safeguards"> | |
| <span> | |
| <Orbit size={15} /> RDKit pipeline | |
| </span> | |
| <span> | |
| <ShieldCheck size={15} /> Research use only | |
| </span> | |
| </div> | |
| </header> | |
| <section className="workspace"> | |
| <ProjectForm onRun={run} disabled={status === "running"} /> | |
| <PipelineSteps status={status} error={error} candidateCount={candidates.length} /> | |
| </section> | |
| <CandidateTable candidates={candidates} /> | |
| {selectedCandidate && <CandidateDetail candidate={selectedCandidate} />} | |
| <footer className="app-footer">powerby:海格礼斯</footer> | |
| </main> | |
| ); | |
| } | |