From 8712bdfec299732b0c5c56df805faf0ae484dbf4 Mon Sep 17 00:00:00 2001 From: Paul Aiden Williams Date: Wed, 12 Aug 2026 16:09:07 -0400 Subject: [PATCH 1/2] 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. +

+ )} +
+ )} From dbbb9433bb88d73460e80b640a94906d38454280 Mon Sep 17 00:00:00 2001 From: navidgh67 Date: Mon, 12 Oct 2026 00:19:19 -0400 Subject: [PATCH 2/2] Keep selected runs listed when the run filters exclude them Runs selected before changing the equipment/project filters stayed plotted and counted toward the selection limit but disappeared from the list, so they couldn't be unchecked and could disable every visible run. They now stay listed, and the count line says how many sit outside the filters. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01SiF54uvxWoEdPxabhv3fFw --- web/components/cross-run-trace-analysis.tsx | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/web/components/cross-run-trace-analysis.tsx b/web/components/cross-run-trace-analysis.tsx index 66b5ebe..3ae4827 100644 --- a/web/components/cross-run-trace-analysis.tsx +++ b/web/components/cross-run-trace-analysis.tsx @@ -212,6 +212,16 @@ export function CrossRunTraceAnalysis() { [runs, selectedEquipment, selectedProject], ); + // Selected runs stay listed even when the filters exclude them, so they can + // still be unchecked (they keep counting toward MAX_SELECTED_RUNS). + const listedRuns = useMemo(() => { + const matching = new Set(filteredRuns.map((run) => run.run_id)); + return runs.filter( + (run) => matching.has(run.run_id) || selectedIds.includes(run.run_id), + ); + }, [filteredRuns, runs, selectedIds]); + const selectedOutsideFilters = listedRuns.length - filteredRuns.length; + const visibleTraces = useMemo( () => (selectedIds.length === 0 ? [] : traces), [selectedIds.length, traces], @@ -435,13 +445,17 @@ export function CrossRunTraceAnalysis() {

Showing {filteredRuns.length.toLocaleString()} of{" "} - {runs.length.toLocaleString()} trace-enabled runs. + {runs.length.toLocaleString()} trace-enabled runs + {selectedOutsideFilters > 0 + ? `, plus ${selectedOutsideFilters.toLocaleString()} selected outside the filters` + : ""} + .

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