132 lines
4.3 KiB
JavaScript

import { useEffect, useState } from "react";
import { Server } from "lucide-react";
import Modal from "../ui/Modal";
import Field from "../ui/Field";
import Button from "../ui/Button";
import { emptyServer } from "../../lib/constants";
export default function ServerFormModal({ open, onClose, initial, onSave }) {
const [form, setForm] = useState(emptyServer);
const [saving, setSaving] = useState(false);
const [error, setError] = useState("");
const isEditing = Boolean(initial?.id);
useEffect(() => {
if (open) {
setForm(
initial
? {
name: initial.name || "",
ipAddress: initial.ipAddress || "",
description: initial.description || "",
proxyPort: initial.proxyPort ?? "",
proxyPath: initial.proxyPath || "",
}
: emptyServer,
);
setError("");
}
}, [open, initial]);
async function submit(event) {
event.preventDefault();
setSaving(true);
setError("");
try {
await onSave({
...form,
proxyPort: form.proxyPort === "" ? null : Number(form.proxyPort),
proxyPath: form.proxyPath.trim() === "" ? null : form.proxyPath.trim(),
});
onClose();
} catch (err) {
setError(err.message);
} finally {
setSaving(false);
}
}
return (
<Modal
open={open}
onClose={onClose}
title={isEditing ? "Edit Server" : "Add Server"}
subtitle={isEditing ? `Editing ${initial.ipAddress}` : "Register a new internal server."}
icon={Server}
size="sm"
footer={
<>
<Button variant="ghost" onClick={onClose} disabled={saving}>
Cancel
</Button>
<Button variant="primary" type="submit" form="server-form" loading={saving}>
{isEditing ? "Save Changes" : "Add Server"}
</Button>
</>
}
>
<form id="server-form" className="grid gap-4" onSubmit={submit}>
<Field label="Server name">
<input
className="input"
required
value={form.name}
onChange={(event) => setForm({ ...form, name: event.target.value })}
placeholder="e.g. Billing Server"
/>
</Field>
<Field label="IP address" hint="or hostname">
<input
className="input mono"
required
value={form.ipAddress}
onChange={(event) => setForm({ ...form, ipAddress: event.target.value })}
placeholder="192.168.1.50"
/>
</Field>
<Field label="Description" hint="optional">
<textarea
className="input min-h-20"
value={form.description}
onChange={(event) => setForm({ ...form, description: event.target.value })}
placeholder="What is this server responsible for?"
/>
</Field>
<div className="grid gap-4 sm:grid-cols-2">
<Field label="Gateway port" hint="optional — common proxy port">
<input
className="input mono"
min="1"
max="65535"
type="number"
value={form.proxyPort}
onChange={(event) => setForm({ ...form, proxyPort: event.target.value })}
placeholder="9999"
/>
</Field>
<Field label="Gateway path" hint="optional — common proxy endpoint">
<input
className="input mono"
value={form.proxyPath}
onChange={(event) => setForm({ ...form, proxyPath: event.target.value })}
placeholder="/api/nginx/app"
/>
</Field>
</div>
{form.proxyPort && (
<p className="rounded-lg border border-line bg-surface-2 px-3 py-2 text-[11px] text-ink-muted">
All services on this server will proxy to{" "}
<span className="mono text-ink-soft">
http://{form.ipAddress || "…"}:{form.proxyPort}
{form.proxyPath || "/api/nginx/app"}
</span>{" "}
with the service domain &amp; port in the body.
</p>
)}
{error && <p className="rounded-lg border border-rose-500/30 bg-rose-500/10 px-3 py-2 text-xs font-medium text-rose-400">{error}</p>}
</form>
</Modal>
);
}