fix: race condition causing wrong symbol data in chart and evaluation
- Add cancelled flags to evaluation and scorecard effects so stale
responses from a previous symbol cannot overwrite current data
- Clear evaluation and scorecard state immediately in pickSymbol so
old data never flashes when switching symbols
- Add key={symbol} to ConfluenceChart to force clean remount on
symbol change
This commit is contained in:
@@ -55,6 +55,9 @@ export function ConfluencePanel() {
|
|||||||
setSymbol(sym);
|
setSymbol(sym);
|
||||||
setSearchQuery(sym);
|
setSearchQuery(sym);
|
||||||
setActiveSymbol(sym);
|
setActiveSymbol(sym);
|
||||||
|
// Clear stale data immediately so old symbol never flashes
|
||||||
|
setEvaluation(null);
|
||||||
|
setScorecard(null);
|
||||||
}, [setActiveSymbol]);
|
}, [setActiveSymbol]);
|
||||||
|
|
||||||
// Sync searchQuery when activeSymbol changes externally (e.g., from another panel)
|
// Sync searchQuery when activeSymbol changes externally (e.g., from another panel)
|
||||||
@@ -62,6 +65,11 @@ export function ConfluencePanel() {
|
|||||||
setSearchQuery(activeSymbol);
|
setSearchQuery(activeSymbol);
|
||||||
}, [activeSymbol]);
|
}, [activeSymbol]);
|
||||||
|
|
||||||
|
// Sync symbol state when activeSymbol changes externally
|
||||||
|
useEffect(() => {
|
||||||
|
setSymbol(activeSymbol);
|
||||||
|
}, [activeSymbol]);
|
||||||
|
|
||||||
// Racks
|
// Racks
|
||||||
const [racks, setRacks] = useState<{ system: Array<{ id: string; name: string }>; user: Array<{ id: string; name: string }> }>({ system: [], user: [] });
|
const [racks, setRacks] = useState<{ system: Array<{ id: string; name: string }>; user: Array<{ id: string; name: string }> }>({ system: [], user: [] });
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -73,18 +81,22 @@ export function ConfluencePanel() {
|
|||||||
const rackId = selectedRackId ?? racks.system[0]?.id ?? null;
|
const rackId = selectedRackId ?? racks.system[0]?.id ?? null;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!symbol) return;
|
if (!symbol) return;
|
||||||
|
let cancelled = false;
|
||||||
api.confluence.evaluation(symbol, { rackId: rackId ?? undefined, limit: 6 })
|
api.confluence.evaluation(symbol, { rackId: rackId ?? undefined, limit: 6 })
|
||||||
.then((r) => setEvaluation(r as Record<string, unknown>))
|
.then((r) => { if (!cancelled) setEvaluation(r as Record<string, unknown>); })
|
||||||
.catch(() => setEvaluation(null));
|
.catch(() => { if (!cancelled) setEvaluation(null); });
|
||||||
|
return () => { cancelled = true; };
|
||||||
}, [symbol, rackId]);
|
}, [symbol, rackId]);
|
||||||
|
|
||||||
// Scorecard
|
// Scorecard
|
||||||
const [scorecard, setScorecard] = useState<{ slots: Array<Record<string, unknown>>; note: string } | null>(null);
|
const [scorecard, setScorecard] = useState<{ slots: Array<Record<string, unknown>>; note: string } | null>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!symbol) return;
|
if (!symbol) return;
|
||||||
|
let cancelled = false;
|
||||||
api.confluence.scorecard(symbol)
|
api.confluence.scorecard(symbol)
|
||||||
.then((r) => setScorecard(r as { slots: Array<Record<string, unknown>>; note: string }))
|
.then((r) => { if (!cancelled) setScorecard(r as { slots: Array<Record<string, unknown>>; note: string }); })
|
||||||
.catch(() => setScorecard(null));
|
.catch(() => { if (!cancelled) setScorecard(null); });
|
||||||
|
return () => { cancelled = true; };
|
||||||
}, [symbol]);
|
}, [symbol]);
|
||||||
|
|
||||||
// Slots
|
// Slots
|
||||||
@@ -194,7 +206,7 @@ export function ConfluencePanel() {
|
|||||||
{/* Signal Timeline chart */}
|
{/* Signal Timeline chart */}
|
||||||
{symbol && (
|
{symbol && (
|
||||||
<CollapsibleSection title="Signal Timeline" defaultOpen>
|
<CollapsibleSection title="Signal Timeline" defaultOpen>
|
||||||
<ConfluenceChart symbol={symbol} />
|
<ConfluenceChart key={symbol} symbol={symbol} />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user