From 43f1b0c13e36b3ff46e6790b65fc53974a13dfd6 Mon Sep 17 00:00:00 2001 From: goodnight Date: Sat, 18 Jul 2026 18:43:42 +0100 Subject: [PATCH] Per-machine detail drawer on dashboard --- web/src/pages/Dashboard.jsx | 90 ++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/web/src/pages/Dashboard.jsx b/web/src/pages/Dashboard.jsx index d5bc5f7..49aa0af 100644 --- a/web/src/pages/Dashboard.jsx +++ b/web/src/pages/Dashboard.jsx @@ -30,6 +30,80 @@ function Badge({ status }) { return {status}; } +// A work order is "open" until it reaches a terminal state. +const OPEN_STATUS = new Set(["pending", "approved", "dispatched"]); +const fmtDate = (iso) => (iso ? new Date(iso).toLocaleString() : "-"); + +function MachineDrawer({ machine, workOrders, downtime, onClose, onSelectWorkOrder }) { + if (!machine) return null; + const history = workOrders.filter((w) => w.machine === machine); + const open = history.filter((w) => OPEN_STATUS.has(w.status)); + const model = downtime?.model || machine; + const location = downtime?.location; + + return ( +
+
e.stopPropagation()}> + +

{machine}

+

{model}{location ? ` - ${location}` : ""}

+ +
+ + + +
+ +
Open faults
+ {open.length === 0 ? ( +

None open.

+ ) : ( +
+ + + + + + {open.map((w) => ( + + + + + + + ))} + +
IDFaultStatusRoot cause
onSelectWorkOrder(w)}>{w.id}{w.fault_code}{w.root_cause}
+
+ )} + +
Work-order history
+ {history.length === 0 ? ( +

No work orders for this machine.

+ ) : ( +
+ + + + + + {history.map((w) => ( + + + + + + + ))} + +
IDFaultStatusCreated
onSelectWorkOrder(w)}>{w.id}{w.fault_code}{fmtDate(w.created_at)}
+
+ )} +
+
+ ); +} + function ConfidenceBadge({ confidence }) { if (confidence == null) return null; const low = confidence < CONFIDENCE_THRESHOLD; @@ -353,6 +427,7 @@ export default function Dashboard() { const [trendData, setTrendData] = useState(null); const [fpmData, setFpmData] = useState(null); const [selected, setSelected] = useState(null); + const [machineDetail, setMachineDetail] = useState(null); const [busy, setBusy] = useState(false); const [loading, setLoading] = useState(true); const [statusFilter, setStatusFilter] = useState(""); @@ -517,7 +592,7 @@ export default function Dashboard() { pending.map((w) => ( setSelected(w)}>{w.id} - {w.machine} + {w.machine ? setMachineDetail(w.machine)}>{w.machine} : "-"} {w.fault_code} {w.root_cause} @@ -567,7 +642,7 @@ export default function Dashboard() { filteredAll.map((w) => ( setSelected(w)}>{w.id} - {w.machine} + {w.machine ? setMachineDetail(w.machine)}>{w.machine} : "-"} {w.fault_code} {w.assigned_to || "-"} @@ -587,6 +662,17 @@ export default function Dashboard() { setSelected(null)} /> + m.machine_id === machineDetail)} + onClose={() => setMachineDetail(null)} + onSelectWorkOrder={(w) => { + setMachineDetail(null); + setSelected(w); + }} + /> +

{t("dashboard.footer")}