import { useEffect, useState } from "react"; import { addUser, createToken, delUser, getSettings, listUsers, patchUser, putSettings } from "./api"; const LABELS = { fal_key: "fal.ai API key", tripo_key: "Tripo API key", meshy_key: "Meshy API key", replicate_token: "Replicate token", openrouter_key: "OpenRouter API key (nano-banana A/B tests)", hf_token: "HuggingFace token (for SF3D / TRELLIS.2 weights)", models_dir: "Models directory", archive_host: "Archive host (rsync)", archive_path: "Archive path", }; export default function Settings({ onClose, onSaved }) { const [data, setData] = useState(null); const [edits, setEdits] = useState({}); const [saving, setSaving] = useState(false); useEffect(() => { getSettings().then(setData); }, []); if (!data) return null; const secretKeys = new Set(data._secret_keys || []); const keys = data._env_keys || []; const save = async () => { setSaving(true); const fresh = await putSettings(edits); setData(fresh); setEdits({}); setSaving(false); onSaved?.(fresh); }; return (
e.stopPropagation()}>

Settings

API keys unlock cloud operators. HuggingFace token lets local SF3D / TRELLIS.2 download their gated weights. Secrets are masked and never written to logs.

{keys.map((k) => { const isSecret = secretKeys.has(k); const current = data[k] || ""; const placeholder = isSecret && current ? "•••••••• (set — leave blank to keep)" : ""; return ( ); })}
); } function Users() { const [users, setUsers] = useState([]); const [nu, setNu] = useState(""); const [np, setNp] = useState(""); const [msg, setMsg] = useState(""); const load = () => listUsers().then(setUsers).catch(() => {}); useEffect(() => { load(); }, []); const create = async () => { setMsg(""); try { await addUser({ username: nu.trim(), password: np }); setNu(""); setNp(""); load(); } catch (e) { setMsg(String(e.message || e).slice(0, 120)); } }; const mkToken = async (username) => { const r = await createToken({ username }); setMsg(`token for ${username} (copy now, shown once): ${r.token}`); }; return (

Users · friends can log in and run LOCAL models only

{users.map((u) => ( ))}
{u.username} {u.role} cap {u.max_active_jobs} {u.role !== "owner" && }
setNu(e.target.value)} /> setNp(e.target.value)} />
{msg &&

{msg}

}
); }