From a9dd4d3bd771b47f0efb4e7f6f7329a5921372b5 Mon Sep 17 00:00:00 2001 From: klopez4212 Date: Tue, 15 Sep 2026 10:30:05 -0400 Subject: [PATCH] Fix desktop onboarding regressions (#7659) ## Summary - restore neutral identity guidance icons and reveal-first private-key copying - keep runtime availability sections contiguous and restore primary onboarding colors - route API-key setup directly to Buzz provider configuration, including slow discovery and signed-out states ## Testing - `pnpm check` - `pnpm test` (6,501 passed) - focused Playwright onboarding coverage (API routing 3/3; visual flow 1/1) Signed-off-by: kenny lopez --- .../src/features/onboarding/ui/BackupStep.tsx | 93 +++++++------------ .../onboarding/ui/DefaultConfigStep.tsx | 4 +- .../onboarding/ui/IdentityKeyIntroduction.tsx | 17 +++- .../ui/SetupStep.acpForcedGate.test.mjs | 8 +- .../src/features/onboarding/ui/SetupStep.tsx | 47 ++++------ .../ui/harnessConnectionOptions.test.mjs | 22 +++++ .../onboarding/ui/harnessConnectionOptions.ts | 26 ++++++ .../e2e/onboarding-agent-defaults.spec.ts | 56 +++++++---- desktop/tests/e2e/onboarding-backup.spec.ts | 45 ++++----- .../onboarding-docked-cta-screenshots.spec.ts | 35 ++++--- 10 files changed, 199 insertions(+), 154 deletions(-) diff --git a/desktop/src/features/onboarding/ui/BackupStep.tsx b/desktop/src/features/onboarding/ui/BackupStep.tsx index f27192e014..e042ac8adc 100644 --- a/desktop/src/features/onboarding/ui/BackupStep.tsx +++ b/desktop/src/features/onboarding/ui/BackupStep.tsx @@ -2,8 +2,6 @@ import { Check, ChevronRight, Copy, - Eye, - EyeOff, FileLock2, ShieldCheck, } from "lucide-react"; @@ -66,9 +64,9 @@ type BackupStepProps = { /** * Onboarding identity-key step — shows the freshly created key, then opens a - * dark backup-options state. The reusable secret stays out of the DOM until an - * explicit reveal or copy action; password backup opens the separate security - * flow. + * dark backup-options state. The new key is visible by default; hovering or + * focusing the key well blurs it and replaces the key with an explicit copy + * action. Password backup opens the separate security flow. * Neither method blocks Next. */ export function BackupStep({ @@ -87,8 +85,6 @@ export function BackupStep({ >("idle"); const [copyError, setCopyError] = React.useState(null); const [nsec, setNsec] = React.useState(null); - const [isRevealed, setIsRevealed] = React.useState(false); - const [isRevealPending, setIsRevealPending] = React.useState(false); const cancelledRef = React.useRef(false); const copiedTimerRef = React.useRef(null); @@ -109,13 +105,30 @@ export function BackupStep({ React.useEffect(() => { cancelledRef.current = false; return () => { - // Back-during-fetch: cancel any in-flight setState calls. + // Back-during-fetch: cancel any in-flight setState calls and release the + // renderer's reference to the freshly generated key. cancelledRef.current = true; + setNsec(null); if (copiedTimerRef.current !== null) window.clearTimeout(copiedTimerRef.current); }; }, []); + React.useEffect(() => { + void getNsec() + .then((value) => { + if (!cancelledRef.current) setNsec(value); + }) + .catch((err: unknown) => { + if (cancelledRef.current) return; + setCopyError( + err instanceof Error + ? err.message + : "Failed to retrieve private key.", + ); + }); + }, []); + const copyKeyToClipboard = React.useCallback(async () => { setCopyState("copying"); setCopyError(null); @@ -139,35 +152,6 @@ export function BackupStep({ } }, [nsec]); - const toggleReveal = React.useCallback(async () => { - if (isRevealed) { - setIsRevealed(false); - return; - } - - setIsRevealPending(true); - setCopyError(null); - try { - const value = nsec ?? (await getNsec()); - if (cancelledRef.current) return; - setNsec(value); - setIsRevealed(true); - } catch (err) { - if (cancelledRef.current) return; - setCopyError( - err instanceof Error ? err.message : "Failed to retrieve private key.", - ); - } finally { - if (!cancelledRef.current) setIsRevealPending(false); - } - }, [isRevealed, nsec]); - - // Never read the credential merely to size its placeholder. The complete - // reusable secret enters the DOM only after an explicit Reveal action. - const maskedKey = React.useMemo( - () => Array.from({ length: nsec?.length ?? 63 }, () => "•").join("\u200b"), - [nsec], - ); const storageDescription = identityStorage === "system-keyring" ? "Buzz keeps your identity key in your system keychain. Your computer may ask for your password when Buzz needs to read the key." @@ -387,39 +371,24 @@ export function BackupStep({ >

- {isRevealed ? nsec : maskedKey} + {nsec}

+
-
{copyError ? ( diff --git a/desktop/src/features/onboarding/ui/DefaultConfigStep.tsx b/desktop/src/features/onboarding/ui/DefaultConfigStep.tsx index 06c732fb44..b3db3b91cb 100644 --- a/desktop/src/features/onboarding/ui/DefaultConfigStep.tsx +++ b/desktop/src/features/onboarding/ui/DefaultConfigStep.tsx @@ -230,7 +230,7 @@ function AgentDefaultsSection({ return (
{configSurfaceLoading ? ( @@ -424,7 +424,7 @@ export function DefaultConfigStep({