submission form cleanup
This commit is contained in:
parent
d44d8448e7
commit
1156984fa6
3 changed files with 112 additions and 49 deletions
|
|
@ -92,9 +92,13 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
const j = t ? JSON.parse(t) : null;
|
const j = t ? JSON.parse(t) : null;
|
||||||
const idVal = j?.data?.id ?? j?.id ?? null;
|
const idVal = j?.data?.id ?? j?.id ?? null;
|
||||||
if (alive) setMeId(idVal ? String(idVal) : null);
|
if (alive) setMeId(idVal ? String(idVal) : null);
|
||||||
} catch { /* ignore */ }
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
return () => { alive = false; };
|
return () => {
|
||||||
|
alive = false;
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -170,7 +174,9 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
if (!dead) setLoading(false);
|
if (!dead) setLoading(false);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
return () => { dead = true; };
|
return () => {
|
||||||
|
dead = true;
|
||||||
|
};
|
||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
if (loading) return <p className="p-6">Loading setting…</p>;
|
if (loading) return <p className="p-6">Loading setting…</p>;
|
||||||
|
|
@ -197,9 +203,16 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
const isMine = meId && ownerId ? meId === ownerId : false;
|
const isMine = meId && ownerId ? meId === ownerId : false;
|
||||||
|
|
||||||
// Small field renderer (label on top, value below)
|
// Small field renderer (label on top, value below)
|
||||||
const Field = ({ label, value, suffix }: { label: string; value: React.ReactNode | string | number | null | undefined; suffix?: string }) => {
|
const Field = ({
|
||||||
const primitive =
|
label,
|
||||||
typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
value,
|
||||||
|
suffix,
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
value: React.ReactNode | string | number | null | undefined;
|
||||||
|
suffix?: string;
|
||||||
|
}) => {
|
||||||
|
const primitive = typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
||||||
const isEmpty = value == null || value === "" || (typeof value === "number" && isNaN(value as number));
|
const isEmpty = value == null || value === "" || (typeof value === "number" && isNaN(value as number));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -240,10 +253,19 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
};
|
};
|
||||||
const DITHER_LABEL = (v: string | undefined) => (v ? v.charAt(0).toUpperCase() + v.slice(1) : "—");
|
const DITHER_LABEL = (v: string | undefined) => (v ? v.charAt(0).toUpperCase() + v.slice(1) : "—");
|
||||||
|
|
||||||
|
const asNumOrNull = (v: any): number | null => {
|
||||||
|
if (typeof v === "number") return Number.isFinite(v) ? v : null;
|
||||||
|
if (typeof v === "string" && v.trim() !== "") {
|
||||||
|
const n = Number(v);
|
||||||
|
return Number.isFinite(n) ? n : null;
|
||||||
|
}
|
||||||
|
// treat booleans/objects as null for numeric-only display
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
// ----- EDIT MODE -----
|
// ----- EDIT MODE -----
|
||||||
if (editMode && rec) {
|
if (editMode && rec) {
|
||||||
const toId = (v: any) =>
|
const toId = (v: any) => (v == null ? "" : typeof v === "object" ? (v.id ?? v.submission_id ?? "") : String(v));
|
||||||
v == null ? "" : typeof v === "object" ? (v.id ?? v.submission_id ?? "") : String(v);
|
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
submission_id: rec.submission_id,
|
submission_id: rec.submission_id,
|
||||||
|
|
@ -307,9 +329,7 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
<div className="grid gap-3">
|
<div className="grid gap-3">
|
||||||
<Field label="Owner" value={ownerLabel(rec.owner)} />
|
<Field label="Owner" value={ownerLabel(rec.owner)} />
|
||||||
<Field label="Uploader" value={rec.uploader || "—"} />
|
<Field label="Uploader" value={rec.uploader || "—"} />
|
||||||
{rec.setting_notes ? (
|
{rec.setting_notes ? <Field label="Notes" value={<p className="whitespace-pre-wrap">{rec.setting_notes}</p>} /> : null}
|
||||||
<Field label="Notes" value={<p className="whitespace-pre-wrap">{rec.setting_notes}</p>} />
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Images (side-by-side thumbnails) */}
|
{/* Images (side-by-side thumbnails) */}
|
||||||
|
|
@ -356,11 +376,7 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
<Field label="Beam Expander" value={optLabel(rec.lens_exp)} suffix="x" />
|
<Field label="Beam Expander" value={optLabel(rec.lens_exp)} suffix="x" />
|
||||||
<Field
|
<Field
|
||||||
label="Scan Lens"
|
label="Scan Lens"
|
||||||
value={
|
value={rec.lens ? `${rec.lens.field_size ?? "—"}${rec.lens.focal_length ? ` / ${rec.lens.focal_length}` : ""}` : "—"}
|
||||||
rec.lens
|
|
||||||
? `${rec.lens.field_size ?? "—"}${rec.lens.focal_length ? ` / ${rec.lens.focal_length}` : ""}`
|
|
||||||
: "—"
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<Field label="Focus" value={rec.focus ?? "—"} suffix="mm" />
|
<Field label="Focus" value={rec.focus ?? "—"} suffix="mm" />
|
||||||
<Field label="Repeat All" value={rec.repeat_all ?? "—"} />
|
<Field label="Repeat All" value={rec.repeat_all ?? "—"} />
|
||||||
|
|
@ -396,9 +412,9 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
<Field label="Speed" value={r.speed ?? "—"} suffix="mm/s" />
|
<Field label="Speed" value={r.speed ?? "—"} suffix="mm/s" />
|
||||||
<Field label="Interval" value={r.interval ?? "—"} suffix="mm" />
|
<Field label="Interval" value={r.interval ?? "—"} suffix="mm" />
|
||||||
<Field label="Angle" value={r.angle ?? "—"} suffix="°" />
|
<Field label="Angle" value={r.angle ?? "—"} suffix="°" />
|
||||||
<Field label="Pass" value={r.pass ?? "—"} />
|
<Field label="Passes" value={r.pass ?? "—"} />
|
||||||
<Field label="Frequency" value={r.frequency ?? "—"} suffix="kHz" />
|
<Field label="Frequency" value={r.frequency ?? "—"} suffix="kHz" />
|
||||||
<Field label="Pulse" value={r.pulse ?? "—"} suffix="ns" />
|
{/* Pulse removed for CO2 */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid sm:grid-cols-2 gap-2 items-center">
|
<div className="grid sm:grid-cols-2 gap-2 items-center">
|
||||||
|
|
@ -425,31 +441,35 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
{rec.line_settings!.map((r: any, i: number) => {
|
{rec.line_settings!.map((r: any, i: number) => {
|
||||||
const perfEnabled = !!r.perf;
|
const perfEnabled = !!r.perf;
|
||||||
const wobbleEnabled = !!r.wobble;
|
const wobbleEnabled = !!r.wobble;
|
||||||
|
const cutVal = asNumOrNull(r.cut);
|
||||||
|
const skipVal = asNumOrNull(r.skip);
|
||||||
|
const stepVal = asNumOrNull(r.step);
|
||||||
|
const sizeVal = asNumOrNull(r.size);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={i} className="border rounded p-3 space-y-2">
|
<div key={i} className="border rounded p-3 space-y-2">
|
||||||
<div className="font-medium">{r.name || `Line ${i + 1}`}</div>
|
<div className="font-medium">{r.name || `Line ${i + 1}`}</div>
|
||||||
|
|
||||||
{/* Base fields – match form order */}
|
{/* Base fields – match form order (Pulse removed) */}
|
||||||
<div className="grid sm:grid-cols-2 gap-2">
|
<div className="grid sm:grid-cols-2 gap-2">
|
||||||
<Field label="Frequency" value={r.frequency ?? "—"} suffix="kHz" />
|
<Field label="Frequency" value={r.frequency ?? "—"} suffix="kHz" />
|
||||||
<Field label="Pulse" value={r.pulse ?? "—"} suffix="ns" />
|
|
||||||
<Field label="Power" value={r.power ?? "—"} suffix="%" />
|
<Field label="Power" value={r.power ?? "—"} suffix="%" />
|
||||||
<Field label="Speed" value={r.speed ?? "—"} suffix="mm/s" />
|
<Field label="Speed" value={r.speed ?? "—"} suffix="mm/s" />
|
||||||
<Field label="Pass" value={r.pass ?? "—"} />
|
<Field label="Passes" value={r.pass ?? "—"} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Perforation row */}
|
{/* Perforation row */}
|
||||||
<div className="grid sm:grid-cols-3 gap-2 items-center">
|
<div className="grid sm:grid-cols-3 gap-2 items-center">
|
||||||
<Field label="Perforation Mode" value={yesNo(perfEnabled)} />
|
<Field label="Perforation Mode" value={yesNo(perfEnabled)} />
|
||||||
{perfEnabled && <Field label="Cut" value={r.cut ?? "—"} suffix="mm" />}
|
{perfEnabled && <Field label="Cut" value={cutVal ?? "—"} suffix="mm" />}
|
||||||
{perfEnabled && <Field label="Skip" value={r.skip ?? "—"} suffix="mm" />}
|
{perfEnabled && <Field label="Skip" value={skipVal ?? "—"} suffix="mm" />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Wobble row */}
|
{/* Wobble row */}
|
||||||
<div className="grid sm:grid-cols-3 gap-2 items-center">
|
<div className="grid sm:grid-cols-3 gap-2 items-center">
|
||||||
<Field label="Wobble" value={yesNo(wobbleEnabled)} />
|
<Field label="Wobble" value={yesNo(wobbleEnabled)} />
|
||||||
{wobbleEnabled && <Field label="Step" value={r.step ?? "—"} suffix="mm" />}
|
{wobbleEnabled && <Field label="Step" value={stepVal ?? "—"} suffix="mm" />}
|
||||||
{wobbleEnabled && <Field label="Size" value={r.size ?? "—"} suffix="mm" />}
|
{wobbleEnabled && <Field label="Size" value={sizeVal ?? "—"} suffix="mm" />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Simple toggle */}
|
{/* Simple toggle */}
|
||||||
|
|
@ -478,9 +498,9 @@ export default function CO2GalvoDetail({ id, editable }: { id: string | number;
|
||||||
<Field label="Power" value={r.power ?? "—"} suffix="%" />
|
<Field label="Power" value={r.power ?? "—"} suffix="%" />
|
||||||
<Field label="Speed" value={r.speed ?? "—"} suffix="mm/s" />
|
<Field label="Speed" value={r.speed ?? "—"} suffix="mm/s" />
|
||||||
<Field label="Interval" value={r.interval ?? "—"} suffix="mm" />
|
<Field label="Interval" value={r.interval ?? "—"} suffix="mm" />
|
||||||
<Field label="Pass" value={r.pass ?? "—"} />
|
<Field label="Passes" value={r.pass ?? "—"} />
|
||||||
<Field label="Frequency" value={r.frequency ?? "—"} suffix="kHz" />
|
<Field label="Frequency" value={r.frequency ?? "—"} suffix="kHz" />
|
||||||
<Field label="Pulse" value={r.pulse ?? "—"} suffix="ns" />
|
{/* Pulse removed for CO2 */}
|
||||||
{isHalftone && <Field label="Halftone Cell" value={r.halftone_cell ?? "—"} />}
|
{isHalftone && <Field label="Halftone Cell" value={r.halftone_cell ?? "—"} />}
|
||||||
{isHalftone && <Field label="Halftone Angle" value={r.halftone_angle ?? "—"} />}
|
{isHalftone && <Field label="Halftone Angle" value={r.halftone_angle ?? "—"} />}
|
||||||
<Field label="Dot Width Adjustment" value={r.dot ?? "—"} suffix="mm" />
|
<Field label="Dot Width Adjustment" value={r.dot ?? "—"} suffix="mm" />
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,9 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
if (alive) setMe(null);
|
if (alive) setMe(null);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
return () => { alive = false; };
|
return () => {
|
||||||
|
alive = false;
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Options loaders (Directus reads)
|
// Options loaders (Directus reads)
|
||||||
|
|
@ -92,7 +94,8 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
let url = "";
|
let url = "";
|
||||||
let map = (rows: any[]) => rows.map((r) => ({ id: String(r.id ?? r.submission_id), label: String(r.name ?? r.model ?? r.opacity ?? r.id) }));
|
let map = (rows: any[]) =>
|
||||||
|
rows.map((r) => ({ id: String(r.id ?? r.submission_id), label: String(r.name ?? r.model ?? r.opacity ?? r.id) }));
|
||||||
|
|
||||||
if (path === "material") url = `${API}/items/material?fields=id,name&limit=1000&sort=name`;
|
if (path === "material") url = `${API}/items/material?fields=id,name&limit=1000&sort=name`;
|
||||||
else if (path === "material_coating") url = `${API}/items/material_coating?fields=id,name&limit=1000&sort=name`;
|
else if (path === "material_coating") url = `${API}/items/material_coating?fields=id,name&limit=1000&sort=name`;
|
||||||
|
|
@ -129,7 +132,10 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
map = (rows) =>
|
map = (rows) =>
|
||||||
rows
|
rows
|
||||||
.slice()
|
.slice()
|
||||||
.sort((a, b) => (parseFloat(a.focal_length ?? "99999") || 99999) - (parseFloat(b.focal_length ?? "99999") || 99999))
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
(parseFloat(a.focal_length ?? "99999") || 99999) - (parseFloat(b.focal_length ?? "99999") || 99999)
|
||||||
|
)
|
||||||
.map((r) => {
|
.map((r) => {
|
||||||
const fs = r.field_size ? `${r.field_size} mm` : "";
|
const fs = r.field_size ? `${r.field_size} mm` : "";
|
||||||
const fl = r.focal_length ? `${r.focal_length} mm` : "";
|
const fl = r.focal_length ? `${r.focal_length} mm` : "";
|
||||||
|
|
@ -158,7 +164,9 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
if (live) setOpts(list);
|
if (live) setOpts(list);
|
||||||
})().catch(() => live && setOpts([]));
|
})().catch(() => live && setOpts([]));
|
||||||
|
|
||||||
return () => { live = false; };
|
return () => {
|
||||||
|
live = false;
|
||||||
|
};
|
||||||
}, [path, includeId]);
|
}, [path, includeId]);
|
||||||
|
|
||||||
return { opts };
|
return { opts };
|
||||||
|
|
@ -172,7 +180,16 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
];
|
];
|
||||||
const RASTER_TYPES = FILL_TYPES;
|
const RASTER_TYPES = FILL_TYPES;
|
||||||
const RASTER_DITHER: Opt[] = [
|
const RASTER_DITHER: Opt[] = [
|
||||||
"threshold", "ordered", "atkinson", "dither", "stucki", "jarvis", "newsprint", "halftone", "sketch", "grayscale",
|
"threshold",
|
||||||
|
"ordered",
|
||||||
|
"atkinson",
|
||||||
|
"dither",
|
||||||
|
"stucki",
|
||||||
|
"jarvis",
|
||||||
|
"newsprint",
|
||||||
|
"halftone",
|
||||||
|
"sketch",
|
||||||
|
"grayscale",
|
||||||
].map((x) => ({ id: x, label: x[0].toUpperCase() + x.slice(1) }));
|
].map((x) => ({ id: x, label: x[0].toUpperCase() + x.slice(1) }));
|
||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
|
|
@ -281,9 +298,15 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
}, [
|
}, [
|
||||||
isEdit,
|
isEdit,
|
||||||
initialValues,
|
initialValues,
|
||||||
mats.opts, coats.opts, colors.opts, opacs.opts,
|
mats.opts,
|
||||||
soft.opts, srcs.opts,
|
coats.opts,
|
||||||
conf.opts, apt.opts, exp.opts,
|
colors.opts,
|
||||||
|
opacs.opts,
|
||||||
|
soft.opts,
|
||||||
|
srcs.opts,
|
||||||
|
conf.opts,
|
||||||
|
apt.opts,
|
||||||
|
exp.opts,
|
||||||
lens.opts,
|
lens.opts,
|
||||||
setValue,
|
setValue,
|
||||||
]);
|
]);
|
||||||
|
|
@ -291,7 +314,8 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
// Image files
|
// Image files
|
||||||
const [photoFile, setPhotoFile] = useState<File | null>(null);
|
const [photoFile, setPhotoFile] = useState<File | null>(null);
|
||||||
const [screenFile, setScreenFile] = useState<File | null>(null);
|
const [screenFile, setScreenFile] = useState<File | null>(null);
|
||||||
const onPick = (setter: (f: File | null) => void) => (e: React.ChangeEvent<HTMLInputElement>) => setter(e.target.files?.[0] ?? null);
|
const onPick = (setter: (f: File | null) => void) => (e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setter(e.target.files?.[0] ?? null);
|
||||||
|
|
||||||
const onSubmit = async (values: any) => {
|
const onSubmit = async (values: any) => {
|
||||||
setSubmitErr(null);
|
setSubmitErr(null);
|
||||||
|
|
@ -354,7 +378,9 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
{/* Hide local H1 in edit mode to avoid duplicate page title */}
|
{/* Hide local H1 in edit mode to avoid duplicate page title */}
|
||||||
{!isEdit && <h1 className="text-xl font-semibold">Submit CO₂ Galvo Setting</h1>}
|
{!isEdit && <h1 className="text-xl font-semibold">Submit CO₂ Galvo Setting</h1>}
|
||||||
{meLabel ? <p className="text-sm text-muted-foreground">Submitting as {meLabel}</p> : null}
|
{meLabel ? <p className="text-sm text-muted-foreground">Submitting as {meLabel}</p> : null}
|
||||||
{submitErr ? <div className="border border-red-500 bg-red-50 text-red-700 rounded px-3 py-2 text-sm">{submitErr}</div> : null}
|
{submitErr ? (
|
||||||
|
<div className="border border-red-500 bg-red-50 text-red-700 rounded px-3 py-2 text-sm">{submitErr}</div>
|
||||||
|
) : null}
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
|
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
|
||||||
|
|
@ -441,11 +467,11 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
<Text label="Name" name={`fill_settings.${i}.name`} register={register} />
|
<Text label="Name" name={`fill_settings.${i}.name`} register={register} />
|
||||||
<Select label="Type" name={`fill_settings.${i}.type`} register={register} options={FILL_TYPES} />
|
<Select label="Type" name={`fill_settings.${i}.type`} register={register} options={FILL_TYPES} />
|
||||||
<Number label="Frequency (kHz)" name={`fill_settings.${i}.frequency`} register={register} step="0.1" />
|
<Number label="Frequency (kHz)" name={`fill_settings.${i}.frequency`} register={register} step="0.1" />
|
||||||
<Number label="Pulse (ns)" name={`fill_settings.${i}.pulse`} register={register} step="0.1" />
|
{/* Pulse removed for CO2 */}
|
||||||
<Number label="Power (%)" name={`fill_settings.${i}.power`} register={register} step="0.1" />
|
<Number label="Power (%)" name={`fill_settings.${i}.power`} register={register} step="0.1" />
|
||||||
<Number label="Speed (mm/s)" name={`fill_settings.${i}.speed`} register={register} step="0.1" />
|
<Number label="Speed (mm/s)" name={`fill_settings.${i}.speed`} register={register} step="0.1" />
|
||||||
<Number label="Interval (mm)" name={`fill_settings.${i}.interval`} register={register} step="0.001" />
|
<Number label="Interval (mm)" name={`fill_settings.${i}.interval`} register={register} step="0.001" />
|
||||||
<Number label="Pass" name={`fill_settings.${i}.pass`} register={register} step="1" />
|
<Number label="Passes" name={`fill_settings.${i}.pass`} register={register} step="1" />
|
||||||
<Number label="Angle (°)" name={`fill_settings.${i}.angle`} register={register} step="1" />
|
<Number label="Angle (°)" name={`fill_settings.${i}.angle`} register={register} step="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -453,7 +479,12 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
<div className="grid md:grid-cols-2 gap-3 items-center">
|
<div className="grid md:grid-cols-2 gap-3 items-center">
|
||||||
<Check label="Auto Rotate" name={`fill_settings.${i}.auto`} register={register} />
|
<Check label="Auto Rotate" name={`fill_settings.${i}.auto`} register={register} />
|
||||||
{autoRotate && (
|
{autoRotate && (
|
||||||
<Number label="Auto Rotate Increment (°)" name={`fill_settings.${i}.increment`} register={register} step="0.001" />
|
<Number
|
||||||
|
label="Auto Rotate Increment (°)"
|
||||||
|
name={`fill_settings.${i}.increment`}
|
||||||
|
register={register}
|
||||||
|
step="0.001"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -483,10 +514,10 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
<div className="grid md:grid-cols-4 gap-3">
|
<div className="grid md:grid-cols-4 gap-3">
|
||||||
<Text label="Name" name={`line_settings.${i}.name`} register={register} />
|
<Text label="Name" name={`line_settings.${i}.name`} register={register} />
|
||||||
<Number label="Frequency (kHz)" name={`line_settings.${i}.frequency`} register={register} step="0.1" />
|
<Number label="Frequency (kHz)" name={`line_settings.${i}.frequency`} register={register} step="0.1" />
|
||||||
<Number label="Pulse (ns)" name={`line_settings.${i}.pulse`} register={register} step="0.1" />
|
{/* Pulse removed for CO2 */}
|
||||||
<Number label="Power (%)" name={`line_settings.${i}.power`} register={register} step="0.1" />
|
<Number label="Power (%)" name={`line_settings.${i}.power`} register={register} step="0.1" />
|
||||||
<Number label="Speed (mm/s)" name={`line_settings.${i}.speed`} register={register} step="0.1" />
|
<Number label="Speed (mm/s)" name={`line_settings.${i}.speed`} register={register} step="0.1" />
|
||||||
<Number label="Pass" name={`line_settings.${i}.pass`} register={register} step="1" />
|
<Number label="Passes" name={`line_settings.${i}.pass`} register={register} step="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Perforation row */}
|
{/* Perforation row */}
|
||||||
|
|
@ -527,7 +558,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
<div className="grid md:grid-cols-4 gap-3">
|
<div className="grid md:grid-cols-4 gap-3">
|
||||||
<Text label="Name" name={`raster_settings.${i}.name`} register={register} />
|
<Text label="Name" name={`raster_settings.${i}.name`} register={register} />
|
||||||
<Number label="Frequency (kHz)" name={`raster_settings.${i}.frequency`} register={register} step="0.1" />
|
<Number label="Frequency (kHz)" name={`raster_settings.${i}.frequency`} register={register} step="0.1" />
|
||||||
<Number label="Pulse (ns)" name={`raster_settings.${i}.pulse`} register={register} step="0.1" />
|
{/* Pulse removed for CO2 */}
|
||||||
<Select label="Type" name={`raster_settings.${i}.type`} register={register} options={RASTER_TYPES} />
|
<Select label="Type" name={`raster_settings.${i}.type`} register={register} options={RASTER_TYPES} />
|
||||||
<Select label="Dither" name={`raster_settings.${i}.dither`} register={register} options={RASTER_DITHER} />
|
<Select label="Dither" name={`raster_settings.${i}.dither`} register={register} options={RASTER_DITHER} />
|
||||||
<Number label="Power (%)" name={`raster_settings.${i}.power`} register={register} step="0.1" />
|
<Number label="Power (%)" name={`raster_settings.${i}.power`} register={register} step="0.1" />
|
||||||
|
|
@ -535,7 +566,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
||||||
<Number label="Interval (mm)" name={`raster_settings.${i}.interval`} register={register} step="0.001" />
|
<Number label="Interval (mm)" name={`raster_settings.${i}.interval`} register={register} step="0.001" />
|
||||||
{/* allow two decimals */}
|
{/* allow two decimals */}
|
||||||
<Number label="Dot Width Adjustment (mm)" name={`raster_settings.${i}.dot`} register={register} step="0.01" />
|
<Number label="Dot Width Adjustment (mm)" name={`raster_settings.${i}.dot`} register={register} step="0.01" />
|
||||||
<Number label="Pass" name={`raster_settings.${i}.pass`} register={register} step="1" />
|
<Number label="Passes" name={`raster_settings.${i}.pass`} register={register} step="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Halftone row */}
|
{/* Halftone row */}
|
||||||
|
|
@ -573,7 +604,13 @@ function Select({
|
||||||
register,
|
register,
|
||||||
options,
|
options,
|
||||||
required,
|
required,
|
||||||
}: { label: string; name: string; register: UseFormRegister<any>; options: Opt[]; required?: boolean }) {
|
}: {
|
||||||
|
label: string;
|
||||||
|
name: string;
|
||||||
|
register: UseFormRegister<any>;
|
||||||
|
options: Opt[];
|
||||||
|
required?: boolean;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm mb-1">
|
<label className="block text-sm mb-1">
|
||||||
|
|
@ -582,7 +619,9 @@ function Select({
|
||||||
<select className="w-full border rounded px-2 py-1" {...register(name, { required })}>
|
<select className="w-full border rounded px-2 py-1" {...register(name, { required })}>
|
||||||
<option value="">—</option>
|
<option value="">—</option>
|
||||||
{options.map((o) => (
|
{options.map((o) => (
|
||||||
<option key={o.id} value={o.id}>{o.label}</option>
|
<option key={o.id} value={o.id}>
|
||||||
|
{o.label}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -616,7 +655,9 @@ function Repeater({ title, fields, onAdd, onRemove, render }: any) {
|
||||||
<fieldset className="border rounded p-3 space-y-3">
|
<fieldset className="border rounded p-3 space-y-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<legend className="font-semibold">{title}</legend>
|
<legend className="font-semibold">{title}</legend>
|
||||||
<button type="button" className="px-2 py-1 border rounded" onClick={onAdd}>+ Add</button>
|
<button type="button" className="px-2 py-1 border rounded" onClick={onAdd}>
|
||||||
|
+ Add
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
|
|
@ -624,7 +665,9 @@ function Repeater({ title, fields, onAdd, onRemove, render }: any) {
|
||||||
<div key={i} className="rounded-lg border bg-muted/20 p-3 space-y-3">
|
<div key={i} className="rounded-lg border bg-muted/20 p-3 space-y-3">
|
||||||
{render(i)}
|
{render(i)}
|
||||||
<div className="pt-1">
|
<div className="pt-1">
|
||||||
<button type="button" className="px-2 py-1 border rounded" onClick={() => onRemove(i)}>Remove</button>
|
<button type="button" className="px-2 py-1 border rounded" onClick={() => onRemove(i)}>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ export default function CO2GalvoList({
|
||||||
const fields = [
|
const fields = [
|
||||||
"submission_id",
|
"submission_id",
|
||||||
"setting_title",
|
"setting_title",
|
||||||
"owner",
|
// IMPORTANT: request the expanded relation only (do NOT include bare 'owner' id)
|
||||||
"owner.id",
|
"owner.id",
|
||||||
"owner.username",
|
"owner.username",
|
||||||
"uploader",
|
"uploader",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue