import React, { useState } from "react"; import { Box, Text, useInput } from "ink"; import TextInput from "ink-text-input"; import { bootstrapPlan, frpInstallPlan, frpInitConfigPlan, DEFAULTS, } from "../lib/tasks.js"; import { defaultInstallDir } from "../lib/frp-config.js"; const FIELDS = [ { key: "serverAddr", label: "Server address" }, { key: "serverPort", label: "Server port" }, { key: "installDir", label: "Install dir" }, ]; export default function FrpConfigForm({ nav, token, purpose }) { const [values, setValues] = useState({ serverAddr: DEFAULTS.serverAddr, serverPort: String(DEFAULTS.serverPort), installDir: defaultInstallDir(), }); const [step, setStep] = useState(0); const [error, setError] = useState(null); useInput((input, key) => { if (key.tab || key.downArrow) { setStep((s) => Math.min(s + 1, FIELDS.length - 1)); return; } if (key.upArrow) { setStep((s) => Math.max(s - 1, 0)); return; } if (key.return) { if (step < FIELDS.length - 1) { setStep((s) => s + 1); return; } submit(); } }); const update = (key) => (value) => { setValues((v) => ({ ...v, [key]: value })); }; const submit = () => { const port = Number(values.serverPort); if (!Number.isInteger(port) || port < 1 || port > 65535) { setError("Server port must be an integer between 1 and 65535."); return; } const options = { token, serverAddr: values.serverAddr.trim() || DEFAULTS.serverAddr, serverPort: port, installDir: values.installDir.trim() || defaultInstallDir(), }; try { let plan; if (purpose === "bootstrap") { plan = bootstrapPlan(options); } else if (purpose === "frp-install") { plan = frpInstallPlan(options); } else if (purpose === "frp-init") { plan = frpInitConfigPlan({ ...options, force: true }); } else { setError(`Unknown purpose: ${purpose}`); return; } nav.replace({ name: "plan", props: { plan, origin: purpose === "bootstrap" ? "main" : "frp" } }); } catch (err) { setError(err.message); } }; return ( FRP configuration ({purpose}): {FIELDS.map((field, index) => ( {index === step ? "› " : " "} {field.label} ))} {error ? ( {error} ) : null} Tab/↓ next · ↑ prev · Enter on last field submits · Esc back ); }