[client] Correlate painted reports with the window generation that sent them

A painted report carried only the window name, so a late report from a popup
that was already closed and replaced marked its replacement ready. The
replacement was then shown before its own frontend had rendered, which is the
blank-dialog case this flow exists to prevent.

Each dialog start URL now carries a monotonic generation token, echoed back by
ReadySignal, and a report whose token no longer matches the live window is
dropped.
This commit is contained in:
Zoltán Papp
2026-09-15 14:43:56 +02:00
parent 9e946e148d
commit cae5a73cec
2 changed files with 90 additions and 16 deletions
@@ -1,4 +1,5 @@
import { useEffect, useRef } from "react";
import { useSearchParams } from "react-router-dom";
import { Events } from "@wailsio/runtime";
import { useStatus } from "@/contexts/StatusContext.tsx";
@@ -6,13 +7,15 @@ const EVENT_WINDOW_PAINTED = "netbird:window-painted";
export const ReadySignal = () => {
const { isReady } = useStatus();
const sent = useRef(false);
const [params] = useSearchParams();
const generation = params.get("gen") ?? "";
const sent = useRef("");
useEffect(() => {
if (!isReady || sent.current) return;
sent.current = true;
void Events.Emit(EVENT_WINDOW_PAINTED);
}, [isReady]);
if (!isReady || sent.current === generation) return;
sent.current = generation;
void Events.Emit(EVENT_WINDOW_PAINTED, generation);
}, [isReady, generation]);
return null;
};