form fixes
This commit is contained in:
parent
d04613ffdc
commit
fd97d67080
1 changed files with 141 additions and 254 deletions
|
|
@ -93,10 +93,10 @@ type EditInitialValues = {
|
|||
laser_soft?: any;
|
||||
repeat_all?: number | null;
|
||||
|
||||
// may exist on CO2 targets
|
||||
lens_conf?: number | null;
|
||||
lens_apt?: number | null;
|
||||
lens_exp?: number | null;
|
||||
// CO2 extras (stored as relations -> ids)
|
||||
lens_conf?: any;
|
||||
lens_apt?: any;
|
||||
lens_exp?: any;
|
||||
|
||||
fill_settings?: any[] | null;
|
||||
line_settings?: any[] | null;
|
||||
|
|
@ -114,6 +114,9 @@ function normalizeForReset(iv: EditInitialValues) {
|
|||
source: idToString(iv.source),
|
||||
lens: idToString(iv.lens),
|
||||
laser_soft: idToString(iv.laser_soft),
|
||||
lens_conf: idToString(iv.lens_conf),
|
||||
lens_apt: idToString(iv.lens_apt),
|
||||
lens_exp: idToString(iv.lens_exp),
|
||||
|
||||
// Arrays: coerce dropdown-ish fields to internal enum keys
|
||||
fill_settings: (iv.fill_settings ?? []).map((r: any) => ({
|
||||
|
|
@ -166,7 +169,6 @@ const DIRECTUS_FIELDS: Record<Target, readonly string[]> = {
|
|||
"fill_settings",
|
||||
"line_settings",
|
||||
"raster_settings",
|
||||
// extras
|
||||
"uploader",
|
||||
"lens_conf",
|
||||
"lens_apt",
|
||||
|
|
@ -304,7 +306,7 @@ function useOptions(path: string, forceIncludeId?: string, opts?: { disableNmFil
|
|||
let url = "";
|
||||
let normalize: (rows: any[]) => Opt[] = (rows) =>
|
||||
rows.map((r) => ({
|
||||
id: String(r.id),
|
||||
id: String(r.id ?? r.submission_id ?? r.value),
|
||||
label: String(r.name ?? r.label ?? r.title ?? r.value ?? r.id),
|
||||
}));
|
||||
|
||||
|
|
@ -335,12 +337,10 @@ function useOptions(path: string, forceIncludeId?: string, opts?: { disableNmFil
|
|||
}));
|
||||
};
|
||||
} else if (rawPath === "lens") {
|
||||
// CO2 gantry uses focus lenses; all others use scan lenses
|
||||
if (target === "co2-gantry") {
|
||||
url = `${API}/items/laser_focus_lens?fields=id,name&limit=1000`;
|
||||
normalize = (rows) => rows.map((r) => ({ id: String(r.id), label: String(r.name ?? r.id) }));
|
||||
} else {
|
||||
// SCAN LENSES (fiber, uv, co2-galvo): sort numerically by focal_length
|
||||
url = `${API}/items/laser_scan_lens?fields=id,field_size,focal_length&limit=1000`;
|
||||
normalize = (rows) => {
|
||||
const toNum = (v: any) => {
|
||||
|
|
@ -356,8 +356,15 @@ function useOptions(path: string, forceIncludeId?: string, opts?: { disableNmFil
|
|||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
// NEW: fixed lists for config / aperture / expander
|
||||
else if (rawPath === "laser_scan_lens_config") {
|
||||
url = `${API}/items/laser_scan_lens_config?fields=id,name&limit=1000&sort=name`;
|
||||
} else if (rawPath === "laser_scan_lens_apt") {
|
||||
url = `${API}/items/laser_scan_lens_apt?fields=id,name&limit=1000&sort=name`;
|
||||
} else if (rawPath === "laser_scan_lens_exp") {
|
||||
url = `${API}/items/laser_scan_lens_exp?fields=id,name&limit=1000&sort=name`;
|
||||
} else {
|
||||
// unknown path → empty
|
||||
setOptsState([]);
|
||||
setLoading(false);
|
||||
return;
|
||||
|
|
@ -375,7 +382,6 @@ function useOptions(path: string, forceIncludeId?: string, opts?: { disableNmFil
|
|||
ensured = [{ id: String(forceIncludeId), label: "(current selection)" }, ...mapped];
|
||||
}
|
||||
|
||||
// client-side text filter
|
||||
const needle = (q || "").trim().toLowerCase();
|
||||
const filtered = needle ? ensured.filter((o) => o.label.toLowerCase().includes(needle)) : ensured;
|
||||
|
||||
|
|
@ -501,9 +507,8 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
const sp = useSearchParams();
|
||||
|
||||
const isEdit = isEditProps(props);
|
||||
const edit = isEdit ? props : null; // strongly-typed local when edit
|
||||
const edit = isEdit ? props : null;
|
||||
|
||||
// Initialize as CO2-galvo in edit mode (unless explicitly overridden)
|
||||
const initialFromQuery =
|
||||
(sp.get("target") as Target) ||
|
||||
props.initialTarget ||
|
||||
|
|
@ -516,19 +521,13 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
}
|
||||
}, [isEdit, props.initialTarget, target]);
|
||||
|
||||
// Map collection -> slug used by options selectors
|
||||
const typeForOptions = useMemo(() => {
|
||||
switch (target) {
|
||||
case "settings_fiber":
|
||||
return "fiber";
|
||||
case "settings_uv":
|
||||
return "uv";
|
||||
case "settings_co2gan":
|
||||
return "co2-gantry";
|
||||
case "settings_co2gal":
|
||||
return "co2-galvo";
|
||||
default:
|
||||
return "fiber";
|
||||
case "settings_fiber": return "fiber";
|
||||
case "settings_uv": return "uv";
|
||||
case "settings_co2gan": return "co2-gantry";
|
||||
case "settings_co2gal": return "co2-galvo";
|
||||
default: return "fiber";
|
||||
}
|
||||
}, [target]);
|
||||
|
||||
|
|
@ -547,46 +546,39 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
|
||||
useEffect(() => {
|
||||
let alive = true;
|
||||
|
||||
// use our bearer-only API
|
||||
fetch(`/api/me`, { cache: "no-store", credentials: "include" })
|
||||
.then((r) => (r.ok ? r.json() : Promise.reject(r)))
|
||||
.then((j) => {
|
||||
if (!alive) return;
|
||||
setMe(j || null);
|
||||
})
|
||||
.catch(() => {
|
||||
if (alive) setMeErr("not-signed-in");
|
||||
});
|
||||
|
||||
return () => {
|
||||
alive = false;
|
||||
};
|
||||
.then((j) => { if (!alive) return; setMe(j || null); })
|
||||
.catch(() => { if (alive) setMeErr("not-signed-in"); });
|
||||
return () => { alive = false; };
|
||||
}, []);
|
||||
|
||||
const meLabel = me?.username ?? "";
|
||||
|
||||
// For edit-mode, compute normalized current values once to seed option lists
|
||||
// For edit-mode, compute normalized current values once
|
||||
const current = useMemo(
|
||||
() => (isEdit && edit?.initialValues ? normalizeForReset(edit.initialValues) : null),
|
||||
[isEdit, edit?.initialValues]
|
||||
);
|
||||
|
||||
// Options
|
||||
const mats = useOptions("material", current?.mat || undefined);
|
||||
const mats = useOptions("material", current?.mat || undefined);
|
||||
const coats = useOptions("material_coating", current?.mat_coat || undefined);
|
||||
const colors = useOptions("material_color", current?.mat_color || undefined);
|
||||
const opacs = useOptions("material_opacity", current?.mat_opacity || undefined);
|
||||
const soft = useOptions("laser_software", current?.laser_soft || undefined); // required for ALL targets
|
||||
const srcs = useOptions(`laser_source?target=${typeForOptions}`, current?.source || undefined, {
|
||||
disableNmFilter: isEdit,
|
||||
});
|
||||
const lens = useOptions(`lens?target=${typeForOptions}`, current?.lens || undefined);
|
||||
const soft = useOptions("laser_software", current?.laser_soft || undefined); // required for ALL targets
|
||||
const srcs = useOptions(`laser_source?target=${typeForOptions}`, current?.source || undefined, { disableNmFilter: isEdit });
|
||||
const lens = useOptions(`lens?target=${typeForOptions}`, current?.lens || undefined);
|
||||
|
||||
// NEW: fixed-value dropdowns for galvo configs
|
||||
const lensConf = useOptions("laser_scan_lens_config", current?.lens_conf || undefined);
|
||||
const lensApt = useOptions("laser_scan_lens_apt", current?.lens_apt || undefined);
|
||||
const lensExp = useOptions("laser_scan_lens_exp", current?.lens_exp || undefined);
|
||||
|
||||
// Repeater choice options (LOCAL now, no network)
|
||||
const fillType = { opts: toOpts(FILL_TYPE_OPTIONS), loading: false, setQ: (_: string) => {} };
|
||||
const rasterType = { opts: toOpts(RASTER_TYPE_OPTIONS), loading: false, setQ: (_: string) => {} };
|
||||
const rasterDither = { opts: toOpts(RASTER_DITHER_OPTIONS), loading: false, setQ: (_: string) => {} };
|
||||
const fillType = { opts: toOpts(FILL_TYPE_OPTIONS), loading: false, setQ: (_: string) => {} };
|
||||
const rasterType = { opts: toOpts(RASTER_TYPE_OPTIONS), loading: false, setQ: (_: string) => {} };
|
||||
const rasterDither= { opts: toOpts(RASTER_DITHER_OPTIONS), loading: false, setQ: (_: string) => {} };
|
||||
|
||||
const {
|
||||
register,
|
||||
|
|
@ -609,8 +601,8 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
lens: "",
|
||||
focus: "",
|
||||
laser_soft: "",
|
||||
repeat_all: "", // on all targets
|
||||
// lens config (may be required on CO2 targets)
|
||||
repeat_all: "",
|
||||
// dropdown ids
|
||||
lens_conf: "",
|
||||
lens_apt: "",
|
||||
lens_exp: "",
|
||||
|
|
@ -620,8 +612,8 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
},
|
||||
});
|
||||
|
||||
const fills = useFieldArray({ control, name: "fill_settings" });
|
||||
const lines = useFieldArray({ control, name: "line_settings" });
|
||||
const fills = useFieldArray({ control, name: "fill_settings" });
|
||||
const lines = useFieldArray({ control, name: "line_settings" });
|
||||
const rasters = useFieldArray({ control, name: "raster_settings" });
|
||||
|
||||
// Prefill the form in edit mode
|
||||
|
|
@ -643,31 +635,23 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
focus: iv.focus ?? "",
|
||||
laser_soft: iv.laser_soft ?? "",
|
||||
repeat_all: iv.repeat_all ?? "",
|
||||
lens_conf: (iv as any).lens_conf ?? "",
|
||||
lens_apt: (iv as any).lens_apt ?? "",
|
||||
lens_exp: (iv as any).lens_exp ?? "",
|
||||
fill_settings: iv.fill_settings ?? [],
|
||||
line_settings: iv.line_settings ?? [],
|
||||
raster_settings: iv.raster_settings ?? [],
|
||||
lens_conf: iv.lens_conf ?? "",
|
||||
lens_apt: iv.lens_apt ?? "",
|
||||
lens_exp: iv.lens_exp ?? "",
|
||||
fill_settings: iv.fill_settings ?? [],
|
||||
line_settings: iv.line_settings ?? [],
|
||||
raster_settings: iv.raster_settings ?? [],
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isEdit, edit?.initialValues, reset]);
|
||||
|
||||
// After reset, force RHF values once (covers early case)
|
||||
useEffect(() => {
|
||||
if (!isEdit || !current) return;
|
||||
|
||||
const fieldNames = [
|
||||
"laser_soft",
|
||||
"mat",
|
||||
"mat_coat",
|
||||
"mat_color",
|
||||
"mat_opacity",
|
||||
"source",
|
||||
"lens",
|
||||
"laser_soft", "mat", "mat_coat", "mat_color", "mat_opacity", "source", "lens",
|
||||
"lens_conf", "lens_apt", "lens_exp",
|
||||
] as const;
|
||||
|
||||
const values = getValues();
|
||||
fieldNames.forEach((name) => {
|
||||
const cur = (current as any)[name];
|
||||
|
|
@ -685,29 +669,11 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
const cur = (current as any)[name];
|
||||
if (cur) setValue(name as any, cur, { shouldDirty: false, shouldValidate: false });
|
||||
};
|
||||
apply("mat");
|
||||
apply("mat_coat");
|
||||
apply("mat_color");
|
||||
apply("mat_opacity");
|
||||
apply("laser_soft");
|
||||
apply("source");
|
||||
apply("lens");
|
||||
}, [
|
||||
isEdit,
|
||||
current,
|
||||
setValue,
|
||||
mats.opts,
|
||||
coats.opts,
|
||||
colors.opts,
|
||||
opacs.opts,
|
||||
soft.opts,
|
||||
srcs.opts,
|
||||
lens.opts,
|
||||
]);
|
||||
["mat","mat_coat","mat_color","mat_opacity","laser_soft","source","lens","lens_conf","lens_apt","lens_exp"]
|
||||
.forEach((n) => apply(n as any));
|
||||
}, [isEdit, current, setValue, mats.opts, coats.opts, colors.opts, opacs.opts, soft.opts, srcs.opts, lens.opts, lensConf.opts, lensApt.opts, lensExp.opts]);
|
||||
|
||||
function num(v: any) {
|
||||
return v === "" || v == null ? null : Number(v);
|
||||
}
|
||||
function num(v: any) { return v === "" || v == null ? null : Number(v); }
|
||||
const bool = (v: any) => !!v;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
|
@ -727,9 +693,8 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
return;
|
||||
}
|
||||
|
||||
// full UI payload (same shape the form uses)
|
||||
const fullPayload: any = {
|
||||
target, // kept top-level for route parity
|
||||
target,
|
||||
setting_title: values.setting_title,
|
||||
setting_notes: values.setting_notes || "",
|
||||
mat: values.mat || null,
|
||||
|
|
@ -740,16 +705,16 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
source: values.source || null,
|
||||
lens: values.lens || null,
|
||||
focus: num(values.focus),
|
||||
laser_soft: values.laser_soft || null, // all targets
|
||||
repeat_all: num(values.repeat_all), // all targets
|
||||
laser_soft: values.laser_soft || null,
|
||||
repeat_all: num(values.repeat_all),
|
||||
|
||||
// uploader: set automatically from owner; include only if present on client
|
||||
// uploader: include if we have it; server will also set from owner
|
||||
...(me?.username || me?.email ? { uploader: me?.username ?? me?.email! } : {}),
|
||||
|
||||
// lens config (required for CO2 targets per your list)
|
||||
lens_conf: num(values.lens_conf),
|
||||
lens_apt: num(values.lens_apt),
|
||||
lens_exp: num(values.lens_exp),
|
||||
// CO2 dropdown ids (relations)
|
||||
lens_conf: values.lens_conf || null,
|
||||
lens_apt: values.lens_apt || null,
|
||||
lens_exp: values.lens_exp || null,
|
||||
|
||||
fill_settings: (values.fill_settings || []).map((r: any) => ({
|
||||
name: r.name || "",
|
||||
|
|
@ -801,16 +766,12 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
})),
|
||||
};
|
||||
|
||||
// Whitelist to match collection fields and drop empty strings
|
||||
const directusData = toDirectusData(target, fullPayload);
|
||||
|
||||
// Early guard for the common required field
|
||||
if (!directusData.setting_title) {
|
||||
setSubmitErr("Title is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build prod-compatible flat payload and ALWAYS send multipart
|
||||
const base = isEdit && edit?.submissionId
|
||||
? { target, mode: "edit" as const, submission_id: edit.submissionId }
|
||||
: { target };
|
||||
|
|
@ -818,13 +779,12 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
const flatPayload = {
|
||||
...base,
|
||||
...directusData,
|
||||
// Keep top-level setting_title for route validators
|
||||
setting_title: directusData.setting_title,
|
||||
};
|
||||
|
||||
try {
|
||||
const form = new FormData();
|
||||
form.set("payload", JSON.stringify(flatPayload)); // prod-compatible key
|
||||
form.set("payload", JSON.stringify(flatPayload));
|
||||
if (photoFile) form.set("photo", photoFile, photoFile.name || "photo");
|
||||
if (screenFile) form.set("screen", screenFile, screenFile.name || "screen");
|
||||
|
||||
|
|
@ -840,7 +800,6 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
throw new Error((data as any)?.error || "Submission failed");
|
||||
}
|
||||
|
||||
// Success
|
||||
if (!isEdit) {
|
||||
reset();
|
||||
setPhotoFile(null);
|
||||
|
|
@ -864,16 +823,12 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
|
||||
function onPick(file: File | null, setFile: (f: File | null) => void, setPreview: (s: string) => void) {
|
||||
setFile(file);
|
||||
if (!file) {
|
||||
setPreview("");
|
||||
return;
|
||||
}
|
||||
if (!file) { setPreview(""); return; }
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => setPreview(String(reader.result || ""));
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
// Convenience strings for “Current:” (edit mode)
|
||||
const currentPhotoId =
|
||||
isEdit && typeof edit?.initialValues?.photo === "string" ? (edit!.initialValues.photo as string) : null;
|
||||
const currentScreenId =
|
||||
|
|
@ -881,7 +836,7 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto space-y-4">
|
||||
{/* Target + Software (Software required for ALL targets) */}
|
||||
{/* Target + Software */}
|
||||
<div className="flex flex-wrap gap-3 items-end">
|
||||
<div>
|
||||
<label className="block text-sm mb-1">Target</label>
|
||||
|
|
@ -905,7 +860,7 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
options={soft.opts}
|
||||
loading={soft.loading}
|
||||
onQuery={soft.setQ}
|
||||
required={true}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -953,18 +908,11 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
type="file"
|
||||
accept="image/*"
|
||||
data-role="photo"
|
||||
// Required when creating OR when editing without an existing photo id (until a new file is chosen)
|
||||
required={!currentPhotoId && !photoFile}
|
||||
onChange={(e) => onPick(e.target.files?.[0] ?? null, setPhotoFile, setPhotoPreview)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{photoFile ? (
|
||||
<>
|
||||
Selected: <span className="font-mono">{photoFile.name}</span>
|
||||
</>
|
||||
) : (
|
||||
"Max 25 MB. JPG/PNG/WebP recommended."
|
||||
)}
|
||||
{photoFile ? <>Selected: <span className="font-mono">{photoFile.name}</span></> : "Max 25 MB. JPG/PNG/WebP recommended."}
|
||||
</p>
|
||||
{photoPreview ? <img src={photoPreview} alt="Result preview" className="mt-2 rounded border" /> : null}
|
||||
</div>
|
||||
|
|
@ -984,13 +932,7 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
onChange={(e) => onPick(e.target.files?.[0] ?? null, setScreenFile, setScreenPreview)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{screenFile ? (
|
||||
<>
|
||||
Selected: <span className="font-mono">{screenFile.name}</span>
|
||||
</>
|
||||
) : (
|
||||
"Max 25 MB. JPG/PNG/WebP recommended."
|
||||
)}
|
||||
{screenFile ? <>Selected: <span className="font-mono">{screenFile.name}</span></> : "Max 25 MB. JPG/PNG/WebP recommended."}
|
||||
</p>
|
||||
{screenPreview ? <img src={screenPreview} alt="Settings preview" className="mt-2 rounded border" /> : null}
|
||||
</div>
|
||||
|
|
@ -1004,60 +946,12 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
|
||||
{/* Material / Source / Lens */}
|
||||
<div className="grid md:grid-cols-2 gap-3">
|
||||
<FilterableSelect
|
||||
label="Material"
|
||||
name="mat"
|
||||
register={register}
|
||||
options={mats.opts}
|
||||
loading={mats.loading}
|
||||
onQuery={mats.setQ}
|
||||
required
|
||||
/>
|
||||
<FilterableSelect
|
||||
label="Coating"
|
||||
name="mat_coat"
|
||||
register={register}
|
||||
options={coats.opts}
|
||||
loading={coats.loading}
|
||||
onQuery={coats.setQ}
|
||||
required
|
||||
/>
|
||||
<FilterableSelect
|
||||
label="Color"
|
||||
name="mat_color"
|
||||
register={register}
|
||||
options={colors.opts}
|
||||
loading={colors.loading}
|
||||
onQuery={colors.setQ}
|
||||
required
|
||||
/>
|
||||
<FilterableSelect
|
||||
label="Opacity"
|
||||
name="mat_opacity"
|
||||
register={register}
|
||||
options={opacs.opts}
|
||||
loading={opacs.loading}
|
||||
onQuery={opacs.setQ}
|
||||
required
|
||||
/>
|
||||
<FilterableSelect
|
||||
label="Laser Source"
|
||||
name="source"
|
||||
register={register}
|
||||
options={srcs.opts}
|
||||
loading={srcs.loading}
|
||||
onQuery={srcs.setQ}
|
||||
required
|
||||
/>
|
||||
<FilterableSelect
|
||||
label="Lens"
|
||||
name="lens"
|
||||
register={register}
|
||||
options={lens.opts}
|
||||
loading={lens.loading}
|
||||
onQuery={lens.setQ}
|
||||
required
|
||||
/>
|
||||
<FilterableSelect label="Material" name="mat" register={register} options={mats.opts} loading={mats.loading} onQuery={mats.setQ} required />
|
||||
<FilterableSelect label="Coating" name="mat_coat" register={register} options={coats.opts} loading={coats.loading} onQuery={coats.setQ} required />
|
||||
<FilterableSelect label="Color" name="mat_color" register={register} options={colors.opts} loading={colors.loading} onQuery={colors.setQ} required />
|
||||
<FilterableSelect label="Opacity" name="mat_opacity" register={register} options={opacs.opts} loading={opacs.loading} onQuery={opacs.setQ} required />
|
||||
<FilterableSelect label="Laser Source" name="source" register={register} options={srcs.opts} loading={srcs.loading} onQuery={srcs.setQ} required />
|
||||
<FilterableSelect label="Lens" name="lens" register={register} options={lens.opts} loading={lens.loading} onQuery={lens.setQ} required />
|
||||
</div>
|
||||
|
||||
{/* Focus, thickness, repeat_all */}
|
||||
|
|
@ -1070,16 +964,40 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
</p>
|
||||
</div>
|
||||
|
||||
{/* Lens Configuration (required on CO2 targets per your list) */}
|
||||
{/* Lens Configuration (dropdowns with fixed options) */}
|
||||
{(target === "settings_co2gan" || target === "settings_co2gal") && (
|
||||
<fieldset className="border rounded p-3 space-y-2">
|
||||
<legend className="font-semibold">Lens Configuration</legend>
|
||||
<legend className="font-semibold">Lens Options</legend>
|
||||
<div className="grid md:grid-cols-3 gap-3">
|
||||
<LabeledInput label="Lens Conf" name="lens_conf" type="number" step="1" register={register} required />
|
||||
<FilterableSelect
|
||||
label="Lens Configuration"
|
||||
name="lens_conf"
|
||||
register={register}
|
||||
options={lensConf.opts}
|
||||
loading={lensConf.loading}
|
||||
onQuery={lensConf.setQ}
|
||||
required
|
||||
/>
|
||||
{target === "settings_co2gal" && (
|
||||
<>
|
||||
<LabeledInput label="Lens Aperture" name="lens_apt" type="number" step="1" register={register} required />
|
||||
<LabeledInput label="Lens Expansion" name="lens_exp" type="number" step="1" register={register} required />
|
||||
<FilterableSelect
|
||||
label="Scan Head Aperture"
|
||||
name="lens_apt"
|
||||
register={register}
|
||||
options={lensApt.opts}
|
||||
loading={lensApt.loading}
|
||||
onQuery={lensApt.setQ}
|
||||
required
|
||||
/>
|
||||
<FilterableSelect
|
||||
label="Beam Expander"
|
||||
name="lens_exp"
|
||||
register={register}
|
||||
options={lensExp.opts}
|
||||
loading={lensExp.loading}
|
||||
onQuery={lensExp.setQ}
|
||||
required
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -1097,32 +1015,23 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
{fills.fields.map((f, i) => (
|
||||
<div key={f.id} className="grid md:grid-cols-4 gap-2">
|
||||
<LabeledInput label="Name" name={`fill_settings.${i}.name`} register={register} />
|
||||
<FilterableSelect
|
||||
label="Type"
|
||||
name={`fill_settings.${i}.type`}
|
||||
register={register}
|
||||
options={fillType.opts}
|
||||
loading={false}
|
||||
onQuery={() => {}}
|
||||
placeholder="Select type"
|
||||
/>
|
||||
<FilterableSelect label="Type" name={`fill_settings.${i}.type`} register={register} options={toOpts(FILL_TYPE_OPTIONS)} loading={false} onQuery={() => {}} placeholder="Select type" />
|
||||
<LabeledInput label="Frequency (kHz)" name={`fill_settings.${i}.frequency`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Pulse (ns)" name={`fill_settings.${i}.pulse`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Power (%)" name={`fill_settings.${i}.power`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Speed (mm/s)" name={`fill_settings.${i}.speed`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Interval (mm)" name={`fill_settings.${i}.interval`} type="number" step="0.001" register={register} />
|
||||
<LabeledInput label="Pass" name={`fill_settings.${i}.pass`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Angle (°)" name={`fill_settings.${i}.angle`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Increment" name={`fill_settings.${i}.increment`} type="number" step="0.001" register={register} />
|
||||
<LabeledInput label="Pulse (ns)" name={`fill_settings.${i}.pulse`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Power (%)" name={`fill_settings.${i}.power`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Speed (mm/s)" name={`fill_settings.${i}.speed`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Interval (mm)" name={`fill_settings.${i}.interval`} type="number" step="0.001" register={register} />
|
||||
<LabeledInput label="Pass" name={`fill_settings.${i}.pass`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Angle (°)" name={`fill_settings.${i}.angle`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Increment" name={`fill_settings.${i}.increment`} type="number" step="0.001" register={register} />
|
||||
<div className="flex items-center gap-3">
|
||||
<BoolBox label="Auto" name={`fill_settings.${i}.auto`} register={register} />
|
||||
<BoolBox label="Auto" name={`fill_settings.${i}.auto`} register={register} />
|
||||
<BoolBox label="Cross" name={`fill_settings.${i}.cross`} register={register} />
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<BoolBox label="Flood" name={`fill_settings.${i}.flood`} register={register} />
|
||||
<BoolBox label="Air" name={`fill_settings.${i}.air`} register={register} />
|
||||
<BoolBox label="Air" name={`fill_settings.${i}.air`} register={register} />
|
||||
</div>
|
||||
|
||||
<button type="button" className="px-2 py-1 border rounded md:col-span-4" onClick={() => fills.remove(i)}>
|
||||
Remove
|
||||
</button>
|
||||
|
|
@ -1140,20 +1049,19 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
</div>
|
||||
{lines.fields.map((f, i) => (
|
||||
<div key={f.id} className="grid md:grid-cols-4 gap-2">
|
||||
<LabeledInput label="Name" name={`line_settings.${i}.name`} register={register} />
|
||||
<LabeledInput label="Frequency (kHz)" name={`line_settings.${i}.frequency`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Pulse (ns)" name={`line_settings.${i}.pulse`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Power (%)" name={`line_settings.${i}.power`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Speed (mm/s)" name={`line_settings.${i}.speed`} type="number" step="0.1" register={register} />
|
||||
<BoolBox label="Perf" name={`line_settings.${i}.perf`} register={register} />
|
||||
<BoolBox label="Cut" name={`line_settings.${i}.cut`} register={register} />
|
||||
<BoolBox label="Skip" name={`line_settings.${i}.skip`} register={register} />
|
||||
<LabeledInput label="Pass" name={`line_settings.${i}.pass`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Step" name={`line_settings.${i}.step`} type="number" step="0.001" register={register} />
|
||||
<LabeledInput label="Size" name={`line_settings.${i}.size`} type="number" step="0.001" register={register} />
|
||||
<BoolBox label="Wobble" name={`line_settings.${i}.wobble`} register={register} />
|
||||
<BoolBox label="Air" name={`line_settings.${i}.air`} register={register} />
|
||||
|
||||
<LabeledInput label="Name" name={`line_settings.${i}.name`} register={register} />
|
||||
<LabeledInput label="Frequency (kHz)" name={`line_settings.${i}.frequency`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Pulse (ns)" name={`line_settings.${i}.pulse`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Power (%)" name={`line_settings.${i}.power`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Speed (mm/s)" name={`line_settings.${i}.speed`} type="number" step="0.1" register={register} />
|
||||
<BoolBox label="Perf" name={`line_settings.${i}.perf`} register={register} />
|
||||
<BoolBox label="Cut" name={`line_settings.${i}.cut`} register={register} />
|
||||
<BoolBox label="Skip" name={`line_settings.${i}.skip`} register={register} />
|
||||
<LabeledInput label="Pass" name={`line_settings.${i}.pass`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Step" name={`line_settings.${i}.step`} type="number" step="0.001" register={register} />
|
||||
<LabeledInput label="Size" name={`line_settings.${i}.size`} type="number" step="0.001" register={register} />
|
||||
<BoolBox label="Wobble" name={`line_settings.${i}.wobble`} register={register} />
|
||||
<BoolBox label="Air" name={`line_settings.${i}.air`} register={register} />
|
||||
<button type="button" className="px-2 py-1 border rounded md:col-span-4" onClick={() => lines.remove(i)}>
|
||||
Remove
|
||||
</button>
|
||||
|
|
@ -1165,50 +1073,29 @@ export default function SettingsSubmit(props: CreateProps | EditProps) {
|
|||
<fieldset className="border rounded p-3 space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<legend className="font-semibold">Raster Settings</legend>
|
||||
<button
|
||||
type="button"
|
||||
className="px-2 py-1 border rounded"
|
||||
onClick={() => rasters.append({ type: "uni", dither: "threshold" })}
|
||||
>
|
||||
<button type="button" className="px-2 py-1 border rounded" onClick={() => rasters.append({ type: "uni", dither: "threshold" })}>
|
||||
+ Add
|
||||
</button>
|
||||
</div>
|
||||
{rasters.fields.map((f, i) => (
|
||||
<div key={f.id} className="grid md:grid-cols-4 gap-2">
|
||||
<LabeledInput label="Name" name={`raster_settings.${i}.name`} register={register} />
|
||||
<LabeledInput label="Frequency (kHz)" name={`raster_settings.${i}.frequency`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Pulse (ns)" name={`raster_settings.${i}.pulse`} type="number" step="0.1" register={register} />
|
||||
<FilterableSelect
|
||||
label="Type"
|
||||
name={`raster_settings.${i}.type`}
|
||||
register={register}
|
||||
options={rasterType.opts}
|
||||
loading={false}
|
||||
onQuery={() => {}}
|
||||
placeholder="Select type"
|
||||
/>
|
||||
<FilterableSelect
|
||||
label="Dither"
|
||||
name={`raster_settings.${i}.dither`}
|
||||
register={register}
|
||||
options={rasterDither.opts}
|
||||
loading={false}
|
||||
onQuery={() => {}}
|
||||
placeholder="Select dither"
|
||||
/>
|
||||
<LabeledInput label="Power (%)" name={`raster_settings.${i}.power`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Speed (mm/s)" name={`raster_settings.${i}.speed`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Halftone Cell" name={`raster_settings.${i}.halftone_cell`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Halftone Angle" name={`raster_settings.${i}.halftone_angle`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Interval (mm)" name={`raster_settings.${i}.interval`} type="number" step="0.001" register={register} />
|
||||
<LabeledInput label="Dot" name={`raster_settings.${i}.dot`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Pass" name={`raster_settings.${i}.pass`} type="number" step="1" register={register} />
|
||||
<BoolBox label="Cross" name={`raster_settings.${i}.cross`} register={register} />
|
||||
<LabeledInput label="Name" name={`raster_settings.${i}.name`} register={register} />
|
||||
<LabeledInput label="Frequency (kHz)" name={`raster_settings.${i}.frequency`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Pulse (ns)" name={`raster_settings.${i}.pulse`} type="number" step="0.1" register={register} />
|
||||
<FilterableSelect label="Type" name={`raster_settings.${i}.type`} register={register} options={toOpts(RASTER_TYPE_OPTIONS)} loading={false} onQuery={() => {}} placeholder="Select type" />
|
||||
<FilterableSelect label="Dither" name={`raster_settings.${i}.dither`} register={register} options={toOpts(RASTER_DITHER_OPTIONS)} loading={false} onQuery={() => {}} placeholder="Select dither" />
|
||||
<LabeledInput label="Power (%)" name={`raster_settings.${i}.power`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Speed (mm/s)" name={`raster_settings.${i}.speed`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Halftone Cell" name={`raster_settings.${i}.halftone_cell`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Halftone Angle" name={`raster_settings.${i}.halftone_angle`} type="number" step="1" register={register} />
|
||||
<LabeledInput label="Interval (mm)" name={`raster_settings.${i}.interval`} type="number" step="0.001" register={register} />
|
||||
<LabeledInput label="Dot" name={`raster_settings.${i}.dot`} type="number" step="0.1" register={register} />
|
||||
<LabeledInput label="Pass" name={`raster_settings.${i}.pass`} type="number" step="1" register={register} />
|
||||
<BoolBox label="Cross" name={`raster_settings.${i}.cross`} register={register} />
|
||||
<div className="flex items-center gap-3">
|
||||
<BoolBox label="Inversion" name={`raster_settings.${i}.inversion`} register={register} />
|
||||
<BoolBox label="Air" name={`raster_settings.${i}.air`} register={register} />
|
||||
<BoolBox label="Air" name={`raster_settings.${i}.air`} register={register} />
|
||||
</div>
|
||||
|
||||
<button type="button" className="px-2 py-1 border rounded md:col-span-4" onClick={() => rasters.remove(i)}>
|
||||
Remove
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue