From cf4faafc0ff21b8a212947a78bfe420776c2942a Mon Sep 17 00:00:00 2001 From: Paul Aiden Williams Date: Wed, 12 Aug 2026 16:09:07 -0400 Subject: [PATCH] Update cross-run-trace-analysis.tsx Creates a filter for equipment registry and project, if available. --- web/components/cross-run-trace-analysis.tsx | 194 ++++++++++++++++---- 1 file changed, 162 insertions(+), 32 deletions(-) diff --git a/web/components/cross-run-trace-analysis.tsx b/web/components/cross-run-trace-analysis.tsx index b9784ad..66b5ebe 100644 --- a/web/components/cross-run-trace-analysis.tsx +++ b/web/components/cross-run-trace-analysis.tsx @@ -43,6 +43,11 @@ const COLORS = [ type AxisMode = "relative" | "absolute"; +const ALL_EQUIPMENT = "__all_equipment__"; +const UNASSIGNED_EQUIPMENT = "__unassigned_equipment__"; +const ALL_PROJECTS = "__all_projects__"; +const UNASSIGNED_PROJECT = "__unassigned_project__"; + async function boundedMap( values: T[], task: (value: T) => Promise, @@ -91,6 +96,8 @@ export function CrossRunTraceAnalysis() { const [selectedIds, setSelectedIds] = useState([]); const [traces, setTraces] = useState([]); const [selectedParameter, setSelectedParameter] = useState(""); + const [selectedEquipment, setSelectedEquipment] = useState(ALL_EQUIPMENT); + const [selectedProject, setSelectedProject] = useState(ALL_PROJECTS); const [axisMode, setAxisMode] = useState("relative"); const [smoothEdges, setSmoothEdges] = useState(false); const [showTrend, setShowTrend] = useState(false); @@ -142,6 +149,69 @@ export function CrossRunTraceAnalysis() { }; }, [selectedIds]); + const equipmentOptions = useMemo(() => { + const byId = new Map(); + runs.forEach((run) => { + if (!run.equipment_id) return; + if (!byId.has(run.equipment_id)) { + byId.set( + run.equipment_id, + run.equipment_name || run.equipment_id, + ); + } + }); + return [...byId.entries()] + .map(([id, name]) => ({ id, name })) + .sort((left, right) => + left.name.localeCompare(right.name, undefined, { numeric: true }), + ); + }, [runs]); + + const projectOptions = useMemo(() => { + const byId = new Map(); + runs.forEach((run) => { + if (!run.project_id) return; + if (!byId.has(run.project_id)) { + byId.set(run.project_id, run.project_name || run.project_id); + } + }); + return [...byId.entries()] + .map(([id, name]) => ({ id, name })) + .sort((left, right) => + left.name.localeCompare(right.name, undefined, { numeric: true }), + ); + }, [runs]); + + const hasUnassignedEquipment = useMemo( + () => runs.some((run) => !run.equipment_id), + [runs], + ); + + const hasUnassignedProject = useMemo( + () => runs.some((run) => !run.project_id), + [runs], + ); + + const filteredRuns = useMemo( + () => + runs.filter((run) => { + const equipmentMatches = + selectedEquipment === ALL_EQUIPMENT || + (selectedEquipment === UNASSIGNED_EQUIPMENT + ? !run.equipment_id + : run.equipment_id === selectedEquipment); + + const projectMatches = + selectedProject === ALL_PROJECTS || + (selectedProject === UNASSIGNED_PROJECT + ? !run.project_id + : run.project_id === selectedProject); + + return equipmentMatches && projectMatches; + }), + [runs, selectedEquipment, selectedProject], + ); + const visibleTraces = useMemo( () => (selectedIds.length === 0 ? [] : traces), [selectedIds.length, traces], @@ -317,39 +387,99 @@ export function CrossRunTraceAnalysis() { Loading runs…

) : ( -
- {runs.map((run) => { - const checked = selectedIds.includes(run.run_id); - const disabled = - !checked && selectedIds.length >= MAX_SELECTED_RUNS; - return ( - + + + +

+ Showing {filteredRuns.length.toLocaleString()} of{" "} + {runs.length.toLocaleString()} trace-enabled runs. +

+
+ +
+ {filteredRuns.length > 0 ? ( + filteredRuns.map((run) => { + const checked = selectedIds.includes(run.run_id); + const disabled = + !checked && selectedIds.length >= MAX_SELECTED_RUNS; + return ( + + ); + }) + ) : ( +

+ No trace-enabled runs match the selected equipment and + project filters. +

+ )} +
+ )}