QoL changes and additions
Build and Push Docker Image / build (push) Successful in 45s

This commit is contained in:
jason
2026-04-22 13:16:42 -05:00
parent a165428f14
commit 04ae88ca0d
14 changed files with 1424 additions and 29 deletions
@@ -75,6 +75,7 @@ export default function AssemblyDetailClient({
const router = useRouter();
const [editOpen, setEditOpen] = useState(false);
const [newPartOpen, setNewPartOpen] = useState(false);
const [dupeOpen, setDupeOpen] = useState(false);
return (
<div className="mx-auto max-w-6xl px-4 py-8">
@@ -103,6 +104,9 @@ export default function AssemblyDetailClient({
}
actions={
<>
<Button variant="secondary" onClick={() => setDupeOpen(true)}>
Duplicate
</Button>
<Button variant="secondary" onClick={() => setEditOpen(true)}>
Edit assembly
</Button>
@@ -253,10 +257,97 @@ export default function AssemblyDetailClient({
}}
/>
)}
{dupeOpen && (
<DuplicateAssemblyModal
assembly={assembly}
onClose={() => setDupeOpen(false)}
onCreated={(newAssemblyId) => {
setDupeOpen(false);
router.push(`/admin/projects/${project.id}/assemblies/${newAssemblyId}`);
}}
/>
)}
</div>
);
}
function DuplicateAssemblyModal({
assembly,
onClose,
onCreated,
}: {
assembly: AssemblyInfo;
onClose: () => void;
onCreated: (id: string) => void;
}) {
const [code, setCode] = useState(`${assembly.code}-COPY`);
const [name, setName] = useState(assembly.name);
const [includeOperations, setIncludeOperations] = useState(true);
const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null);
async function submit(e: React.FormEvent) {
e.preventDefault();
setBusy(true);
setError(null);
try {
const res = await apiFetch<{ assembly: { id: string } }>(
`/api/v1/assemblies/${assembly.id}/duplicate`,
{
method: "POST",
body: JSON.stringify({ code, name, includeOperations }),
},
);
onCreated(res.assembly.id);
} catch (err) {
setError(err instanceof ApiClientError ? err.message : "Duplicate failed");
setBusy(false);
}
}
return (
<Modal
open
onClose={onClose}
title={`Duplicate ${assembly.code}`}
footer={
<>
<div className="flex-1" />
<Button variant="secondary" onClick={onClose} disabled={busy}>
Cancel
</Button>
<Button type="submit" form="asm-dup-form" disabled={busy}>
{busy ? "Duplicating…" : "Duplicate"}
</Button>
</>
}
>
<form id="asm-dup-form" onSubmit={submit} className="space-y-4">
<p className="text-sm text-slate-600">
Creates a new assembly in the same project. Every part is cloned along
with its file attachments. Operations get fresh QR codes and reset to
pending.
</p>
<Field label="New code" required hint="Must be unique within this project.">
<Input value={code} onChange={(e) => setCode(e.target.value)} required autoFocus />
</Field>
<Field label="Name">
<Input value={name} onChange={(e) => setName(e.target.value)} />
</Field>
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={includeOperations}
onChange={(e) => setIncludeOperations(e.target.checked)}
/>
Copy operations (fresh QR codes, status reset to pending)
</label>
<ErrorBanner message={error} />
</form>
</Modal>
);
}
function EditAssemblyModal({
assembly,
onClose,