| "use client"; |
|
|
| import { useCallback, useEffect, useState } from "react"; |
|
|
| const PHYLO_BACKEND = |
| process.env.NEXT_PUBLIC_PHYLO_BACKEND_URL || "http://127.0.0.1:8601"; |
|
|
| type Provider = "hub-runpod" | "hub-slurm" | "runpod-direct"; |
|
|
| const LABELS: Record<Provider, string> = { |
| "hub-runpod": "Hub (RunPod)", |
| "hub-slurm": "Hub (SLURM)", |
| "runpod-direct": "RunPod Direct", |
| }; |
|
|
| export default function ComputeProviderSelector() { |
| const [provider, setProvider] = useState<Provider>("hub-runpod"); |
| const [runpodConfigured, setRunpodConfigured] = useState(false); |
| const [loading, setLoading] = useState(true); |
|
|
| useEffect(() => { |
| (async () => { |
| try { |
| const res = await fetch(`${PHYLO_BACKEND}/api/settings`); |
| if (res.ok) { |
| const data = await res.json(); |
| setProvider(data.compute_provider); |
| setRunpodConfigured(data.runpod_configured); |
| } |
| } catch { |
| |
| } finally { |
| setLoading(false); |
| } |
| })(); |
| }, []); |
|
|
| const onChange = useCallback(async (newProvider: Provider) => { |
| setProvider(newProvider); |
| try { |
| await fetch(`${PHYLO_BACKEND}/api/settings`, { |
| method: "PATCH", |
| headers: { "Content-Type": "application/json" }, |
| body: JSON.stringify({ compute_provider: newProvider }), |
| }); |
| } catch { |
| |
| } |
| }, []); |
|
|
| if (loading) return null; |
|
|
| return ( |
| <div className="flex items-center gap-1.5"> |
| <svg |
| className="w-3 h-3 text-muted-fg" |
| viewBox="0 0 24 24" |
| fill="none" |
| stroke="currentColor" |
| strokeWidth={2} |
| > |
| <rect x="4" y="4" width="16" height="16" rx="2" /> |
| <path d="M9 9h6v6H9z" /> |
| </svg> |
| <select |
| value={provider} |
| onChange={(e) => onChange(e.target.value as Provider)} |
| className="text-[10px] bg-transparent border border-border rounded-md px-1.5 py-0.5 text-foreground-dim focus:outline-none focus:border-accent cursor-pointer" |
| title="Compute provider β where GPU jobs run" |
| > |
| {(Object.keys(LABELS) as Provider[]).map((p) => ( |
| <option key={p} value={p} disabled={p === "runpod-direct" && !runpodConfigured}> |
| {LABELS[p]}{p === "runpod-direct" && !runpodConfigured ? " (no key)" : ""} |
| </option> |
| ))} |
| </select> |
| </div> |
| ); |
| } |
|
|