Polish sidebar update and relay cards (#1009)

This commit is contained in:
klopez4212
2026-06-17 18:48:35 +01:00
committed by GitHub
parent 1a37ee3951
commit d4cd919b85
37 changed files with 2077 additions and 332 deletions
+49 -8
View File
@@ -5,7 +5,7 @@
* Deliberately uses `relayClient.preconnect()` + `queryClient.invalidateQueries()`
* rather than the full `reconnectWorkspace()` path, which unmounts the entire
* React tree and clears drafts. The goal here is a transparent re-handshake
* when WARP VPN comes back online; the user should not lose their in-progress
* when the transport comes back online; the user should not lose their in-progress
* compose state.
*/
@@ -16,8 +16,30 @@ import { toast } from "sonner";
import { relayClient } from "@/shared/api/relayClient";
const RECONNECT_HOOK_TIMEOUT_MS = 20_000;
const RELAY_PRECONNECT_TIMEOUT_MS = 15_000;
function withTimeout<T>(
promise: Promise<T>,
timeoutMs: number,
label: string,
): Promise<T> {
let timeoutId: number | null = null;
const timeout = new Promise<never>((_, reject) => {
timeoutId = window.setTimeout(() => {
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
}, timeoutMs);
});
return Promise.race([promise, timeout]).finally(() => {
if (timeoutId !== null) {
window.clearTimeout(timeoutId);
}
});
}
export function useReconnectRelay(): {
reconnect: () => Promise<void>;
reconnect: () => Promise<boolean>;
isPending: boolean;
} {
const queryClient = useQueryClient();
@@ -28,25 +50,44 @@ export function useReconnectRelay(): {
const inFlightRef = React.useRef(false);
const reconnect = React.useCallback(async () => {
if (inFlightRef.current) return;
if (inFlightRef.current) return false;
inFlightRef.current = true;
setIsPending(true);
try {
// Run transport-layer reconnect hook (e.g. WARP VPN re-auth for internal builds).
// Run the transport-layer reconnect hook configured by internal builds.
// No-op in OSS builds. Non-fatal — transport failure shouldn't block relay reconnect.
try {
await invoke("relay_reconnect_hook");
await withTimeout(
invoke("relay_reconnect_hook"),
RECONNECT_HOOK_TIMEOUT_MS,
"reconnect hook",
);
} catch (err) {
console.warn("[useReconnectRelay] reconnect hook failed:", err);
}
await relayClient.preconnect();
await queryClient.invalidateQueries();
await withTimeout(
relayClient.preconnect(),
RELAY_PRECONNECT_TIMEOUT_MS,
"relay preconnect",
);
// Let callers render the recovered/connected state before refetching the
// sidebar data. The refetch can briefly swap the sidebar into loading UI.
window.setTimeout(() => {
void queryClient.invalidateQueries().catch((error) => {
console.error(
"[useReconnectRelay] failed to refresh queries after reconnect:",
error,
);
});
}, 0);
// No success toast — the banner auto-hides once the connection state
// transitions back to "connected", which is the user-visible confirmation.
return true;
} catch (err) {
toast.error("Reconnect failed — check your VPN or network.");
toast.error("Reconnect failed — check your network.");
console.error("[useReconnectRelay] reconnect failed:", err);
return false;
} finally {
inFlightRef.current = false;
setIsPending(false);