step 9 and cleanup
Build and Push Docker Image / build (push) Successful in 1m4s

This commit is contained in:
jason
2026-04-22 09:27:01 -05:00
parent c8c86c9ca4
commit e0dfac2d48
18 changed files with 1521 additions and 85 deletions
@@ -54,6 +54,7 @@ export interface OperationRow {
id: string;
sequence: number;
name: string;
kind: string;
machineId: string | null;
machineName: string | null;
templateId: string | null;
@@ -89,6 +90,7 @@ const STATUS_TONE: Record<string, "slate" | "blue" | "green" | "amber" | "red">
in_progress: "blue",
partial: "amber",
completed: "green",
qc_failed: "red",
};
const STATUS_LABEL: Record<string, string> = {
@@ -96,6 +98,7 @@ const STATUS_LABEL: Record<string, string> = {
in_progress: "In progress",
partial: "Partial",
completed: "Completed",
qc_failed: "QC failed",
};
function formatBytes(n: number) {
@@ -295,6 +298,26 @@ function OperationsSection({
}
}
async function resetQc(op: OperationRow) {
if (
!confirm(
`Clear QC failure on step ${op.sequence}. ${op.name}? The step will reopen for rework; the failing QC record stays on file.`,
)
) {
return;
}
setBusyId(op.id);
setError(null);
try {
await apiFetch(`/api/v1/operations/${op.id}/qc-reset`, { method: "POST" });
onChange();
} catch (err) {
setError(err instanceof ApiClientError ? err.message : "Reset failed");
} finally {
setBusyId(null);
}
}
return (
<section>
<div className="flex items-center justify-between mb-3">
@@ -322,7 +345,10 @@ function OperationsSection({
<tr key={op.id} className="border-b border-slate-100 last:border-0">
<td className="px-3 py-3 text-slate-600">{op.sequence}</td>
<td className="px-3 py-3">
<div className="font-medium">{op.name}</div>
<div className="font-medium flex items-center gap-2">
<span>{op.name}</span>
{op.kind === "qc" ? <Badge tone="blue">QC step</Badge> : null}
</div>
{op.templateName ? (
<div className="text-xs text-slate-500">from {op.templateName}</div>
) : null}
@@ -376,6 +402,16 @@ function OperationsSection({
<Button variant="ghost" size="sm" onClick={() => setEdit(op)} disabled={busyId !== null}>
Edit
</Button>
{op.status === "qc_failed" ? (
<Button
variant="ghost"
size="sm"
onClick={() => resetQc(op)}
disabled={busyId !== null}
>
Reset QC
</Button>
) : null}
<Button
variant="ghost"
size="sm"
@@ -528,6 +564,9 @@ function OperationModal({
const editing = !!operation;
const [templateId, setTemplateId] = useState(operation?.templateId ?? "");
const [name, setName] = useState(operation?.name ?? "");
const [kind, setKind] = useState<"work" | "qc">(
(operation?.kind as "work" | "qc") ?? "work",
);
const [machineId, setMachineId] = useState(operation?.machineId ?? "");
const [settings, setSettings] = useState(operation?.settings ?? "");
const [materialNotes, setMaterialNotes] = useState(operation?.materialNotes ?? "");
@@ -563,6 +602,7 @@ function OperationModal({
const body = {
templateId: templateId || null,
name,
kind,
machineId: machineId || null,
settings,
materialNotes,
@@ -623,6 +663,15 @@ function OperationModal({
<Field label="Name" required>
<Input value={name} onChange={(e) => setName(e.target.value)} required />
</Field>
<Field
label="Kind"
hint='"Work" is a normal production step. "QC" is a dedicated inspection step — close always demands a pass/fail record and unit counts are ignored.'
>
<Select value={kind} onChange={(e) => setKind(e.target.value as "work" | "qc")}>
<option value="work">Work production step</option>
<option value="qc">QC dedicated inspection</option>
</Select>
</Field>
<Field label="Machine">
<Select value={machineId} onChange={(e) => setMachineId(e.target.value)}>
<option value=""> none </option>
@@ -669,12 +718,16 @@ function OperationModal({
<span>QC check required on close-out</span>
</label>
{editing && (
<Field label="Status">
<Field
label="Status"
hint="Use QC-failed only if you need to block a step out-of-band; the normal path is for the operator's Done/fail to set it."
>
<Select value={status} onChange={(e) => setStatus(e.target.value)}>
<option value="pending">Pending</option>
<option value="in_progress">In progress</option>
<option value="partial">Partial</option>
<option value="completed">Completed</option>
<option value="qc_failed">QC failed</option>
</Select>
</Field>
)}