diff --git a/gui-ts/src/ui/App.tsx b/gui-ts/src/ui/App.tsx index 6629924..ae2f8e1 100644 --- a/gui-ts/src/ui/App.tsx +++ b/gui-ts/src/ui/App.tsx @@ -48,6 +48,7 @@ export function App() { const [surfaceCardQaError, setSurfaceCardQaError] = useState(null); const [validatingSurfaceCard, setValidatingSurfaceCard] = useState(false); const hydrated = useRef(false); + const latestRunToken = useRef(0); const engineeringChecks = useMemo(() => runEngineeringChecks(store.state), [store.state]); useEffect(() => { @@ -96,6 +97,8 @@ export function App() { }, [parsedSurfaceCard]); const handleRun = useCallback(async () => { + const runToken = latestRunToken.current + 1; + latestRunToken.current = runToken; if (engineeringChecks.hasBlockingError) { setError("Please fix blocking engineering checks before running the solver."); setStatusMessage("Blocked by engineering checks"); @@ -133,6 +136,9 @@ export function App() { fourierHarmonics: runSettings.outputOptions.fourierHarmonics } }); + if (latestRunToken.current !== runToken) { + return; + } setResult(resp); const dt = (performance.now() - t0) / 1000; setElapsed(dt); @@ -140,10 +146,15 @@ export function App() { setStatusMessage(`Done in ${dt.toFixed(1)}s`); setActiveTab("tab-results"); } catch (e) { + if (latestRunToken.current !== runToken) { + return; + } setError(e instanceof Error ? e.message : String(e)); setStatusMessage("Error"); } finally { - setLoading(false); + if (latestRunToken.current === runToken) { + setLoading(false); + } } }, [engineeringChecks.hasBlockingError, parsedSurfaceCard, runSettings, store.state]); diff --git a/gui-ts/src/ui/tabs/ResultsTab.tsx b/gui-ts/src/ui/tabs/ResultsTab.tsx index c105564..6934d4f 100644 --- a/gui-ts/src/ui/tabs/ResultsTab.tsx +++ b/gui-ts/src/ui/tabs/ResultsTab.tsx @@ -122,6 +122,12 @@ export function ResultsTab({ } return [fdmSeries.position, fdmSeries.polished, fdmSeries.downhole] as AlignedData; }, [fdm, fea]); + const hasCardLengthMismatch = useMemo(() => { + const fdmSeries = toSeries(fdm ?? undefined); + const feaSeries = toSeries(fea ?? undefined); + if (!fdmSeries || !feaSeries) return false; + return fdmSeries.position.length !== feaSeries.position.length; + }, [fdm, fea]); const dynacardOptions = useMemo(() => { const seriesCount = fea ? 5 : 3; @@ -364,6 +370,11 @@ export function ResultsTab({
+ {hasCardLengthMismatch && ( +
+ FDM and FEA card lengths differ; chart overlay is limited to FDM series for this run. +
+ )} {dynacardData ? ( ) : (