Files
server-config-cli/src/screens/ProxyForm.jsx
2026-05-11 17:19:13 +08:00

131 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from "react";
import { Box, Text, useInput } from "ink";
import TextInput from "ink-text-input";
import { frpAddProxyPlan } from "../lib/tasks.js";
const FIELDS = [
{ key: "name", label: "Name (e.g. ssh)" },
{ key: "type", label: "Type" },
{ key: "localIp", label: "Local IP" },
{ key: "localPort", label: "Local port" },
{ key: "remotePort", label: "Remote port" },
];
export default function ProxyForm({ nav }) {
const [values, setValues] = useState({
name: "",
type: "tcp",
localIp: "127.0.0.1",
localPort: "",
remotePort: "",
});
const [restart, setRestart] = useState(true);
const [step, setStep] = useState(0);
const [error, setError] = useState(null);
const totalRows = FIELDS.length + 1;
useInput((input, key) => {
if (key.tab || key.downArrow) {
setStep((s) => Math.min(s + 1, totalRows - 1));
return;
}
if (key.upArrow) {
setStep((s) => Math.max(s - 1, 0));
return;
}
if (step === totalRows - 1) {
if (input === " ") {
setRestart((r) => !r);
return;
}
if (key.return) {
submit();
return;
}
}
if (key.return) {
if (step < totalRows - 1) {
setStep((s) => s + 1);
return;
}
submit();
}
});
const update = (key) => (value) => {
setValues((v) => ({ ...v, [key]: value }));
};
const submit = () => {
setError(null);
const localPort = Number(values.localPort);
const remotePort = Number(values.remotePort);
if (!Number.isInteger(localPort) || localPort < 1 || localPort > 65535) {
setError("Local port must be an integer in [1, 65535].");
return;
}
if (!Number.isInteger(remotePort) || remotePort < 1 || remotePort > 65535) {
setError("Remote port must be an integer in [1, 65535].");
return;
}
try {
const plan = frpAddProxyPlan({
name: values.name.trim(),
type: values.type.trim() || "tcp",
localIp: values.localIp.trim() || "127.0.0.1",
localPort,
remotePort,
restart,
});
nav.replace({ name: "plan", props: { plan, origin: "frp" } });
} catch (err) {
setError(err.message);
}
};
return (
<Box flexDirection="column">
<Text>Add frp proxy:</Text>
<Box flexDirection="column" marginTop={1}>
{FIELDS.map((field, index) => (
<Box key={field.key}>
<Box width={20}>
<Text color={index === step ? "cyan" : undefined}>
{index === step ? " " : " "}
{field.label}
</Text>
</Box>
<TextInput
value={values[field.key]}
onChange={update(field.key)}
focus={index === step}
/>
</Box>
))}
<Box>
<Box width={20}>
<Text color={step === FIELDS.length ? "cyan" : undefined}>
{step === FIELDS.length ? " " : " "}
Restart frpc
</Text>
</Box>
<Text>[{restart ? "x" : " "}] (Space to toggle)</Text>
</Box>
</Box>
{error ? (
<Box marginTop={1}>
<Text color="red">{error}</Text>
</Box>
) : null}
<Box marginTop={1}>
<Text dimColor>Tab/ next · prev · Space toggles restart · Enter on last submits</Text>
</Box>
</Box>
);
}