"use client"; import { useState } from "react"; import type { LocationDraft, LocationResult } from "../actions"; // ADD AND EDIT ARE ONE FORM, because they are one set of rules: the id shape, // the absolute root, the label that falls back to the id, and the opt-in. The // only difference is that an id is CHOSEN once and never changed — it is what // `defaultLocationId` and every action refer to — so in edit mode the field is // shown and disabled rather than hidden, which keeps the row readable. // // TYPES ONLY, FROM THE ACTION FILE. This is a "use client" file: it may not // reach `lib/storageVolumes.ts` or the storage controller (both import execa, // and `next build` fails on `node:child_process` in a client bundle). The // server actions it calls are the wire, and `LocationDraft` is a plain object. type Props = { mode: "add" | "edit"; initial?: { id: string; label: string; root: string; autoRepoint: boolean; isDefault: boolean; }; submit: (draft: LocationDraft) => Promise; onDone?: () => void; onCancel?: () => void; }; export function LocationForm({ mode, initial, submit, onDone, onCancel }: Props) { const [id, setId] = useState(initial?.id ?? ""); const [label, setLabel] = useState(initial?.label ?? ""); const [root, setRoot] = useState(initial?.root ?? ""); const [autoRepoint, setAutoRepoint] = useState(initial?.autoRepoint ?? false); const [makeDefault, setMakeDefault] = useState(initial?.isDefault ?? false); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); async function run() { setBusy(true); setError(null); const result = await submit({ id, label, root, autoRepoint, makeDefault }); setBusy(false); if (!result.ok) { setError(result.error); return; } if (mode === "add") { setId(""); setLabel(""); setRoot(""); setAutoRepoint(false); setMakeDefault(false); } onDone?.(); } return (
{error && (

{error}

)}
{onCancel && ( )}
); }