From 497b75dc73c8e724a603b300dcb4849f6f1c86a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Barreiro?= <52393857+BarreiroT@users.noreply.github.com> Date: Wed, 6 May 2026 22:48:07 +0200 Subject: [PATCH] Dismiss onboarding after login (#10562) * Dismiss onboarding after login * add visual feedback when loading * await the login --- .../components/onboarding/OnboardingView.tsx | 101 +++++++++++++----- 1 file changed, 76 insertions(+), 25 deletions(-) diff --git a/webview-ui/src/components/onboarding/OnboardingView.tsx b/webview-ui/src/components/onboarding/OnboardingView.tsx index 5b490bb4e6..376103f362 100644 --- a/webview-ui/src/components/onboarding/OnboardingView.tsx +++ b/webview-ui/src/components/onboarding/OnboardingView.tsx @@ -1,7 +1,7 @@ import type { ModelInfo } from "@shared/api" import type { OnboardingModel, OnboardingModelGroup, OpenRouterModelInfo } from "@shared/proto/index.cline" import { AlertCircleIcon, CircleCheckIcon, CircleIcon, ListIcon, LoaderCircleIcon, ZapIcon } from "lucide-react" -import { useCallback, useEffect, useMemo, useState } from "react" +import { useCallback, useEffect, useMemo, useRef, useState } from "react" import ClineLogoWhite from "@/assets/ClineLogoWhite" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" @@ -268,6 +268,8 @@ const OnboardingStepContent = ({ const OnboardingViewContent = ({ onboardingModels }: { onboardingModels: OnboardingModelGroup }) => { const { handleFieldsChange } = useApiConfigurationHandlers() const { openRouterModels, hideSettings, hideAccount, setShowWelcome } = useExtensionState() + const loginAttemptIdRef = useRef(0) + const loginLoadingTimeoutRef = useRef | null>(null) const [stepNumber, setStepNumber] = useState(0) const [isActionLoading, setIsActionLoading] = useState(false) @@ -286,6 +288,14 @@ const OnboardingViewContent = ({ onboardingModels }: { onboardingModels: Onboard setSelectedModelId(userGroupInitModel.id) }, [userType, models]) + useEffect(() => { + return () => { + if (loginLoadingTimeoutRef.current) { + clearTimeout(loginLoadingTimeoutRef.current) + } + } + }, []) + const onUserTypeClick = useCallback((userType: NEW_USER_TYPE) => { setUserType(userType) const action = @@ -317,12 +327,52 @@ const OnboardingViewContent = ({ onboardingModels }: { onboardingModels: Onboard actModeApiProvider: "cline", }) } + + await StateServiceClient.setWelcomeViewCompleted({ value: true }).catch(() => {}) + setShowWelcome(false) hideAccount() hideSettings() const action = "onboarding_completed" StateServiceClient.captureOnboardingProgress({ step, modelSelected, action, completed: true }) }, - [hideAccount, hideSettings, handleFieldsChange, selectedModelId, openRouterModels], + [hideAccount, hideSettings, handleFieldsChange, selectedModelId, openRouterModels, setShowWelcome], + ) + + const loginAndFinishOnboarding = useCallback( + async (updateModelId: boolean, step: number) => { + const loginAttemptId = loginAttemptIdRef.current + 1 + loginAttemptIdRef.current = loginAttemptId + + if (loginLoadingTimeoutRef.current) { + clearTimeout(loginLoadingTimeoutRef.current) + } + + setIsActionLoading(true) + // Allow the user to re-attempt after 10s + loginLoadingTimeoutRef.current = setTimeout(() => { + if (loginAttemptIdRef.current === loginAttemptId) { + setIsActionLoading(false) + } + }, 10_000) + + await AccountServiceClient.accountLoginClicked({}) + .catch((error) => { + console.error("Failed to log in during onboarding:", error) + }) + .finally(() => { + if (loginAttemptIdRef.current !== loginAttemptId) { + return + } + if (loginLoadingTimeoutRef.current) { + clearTimeout(loginLoadingTimeoutRef.current) + loginLoadingTimeoutRef.current = null + } + }) + + await finishOnboarding(updateModelId, step) + setIsActionLoading(false) + }, + [finishOnboarding], ) const handleFooterAction = useCallback( @@ -330,18 +380,10 @@ const OnboardingViewContent = ({ onboardingModels }: { onboardingModels: Onboard switch (action) { case "signup": setStepNumber(stepNumber + 1) - setIsActionLoading(true) - await AccountServiceClient.accountLoginClicked({}) - .catch(() => {}) - .finally(() => setIsActionLoading(false)) - await finishOnboarding(true, stepNumber + 1) + await loginAndFinishOnboarding(true, stepNumber + 1) break case "signin": - setIsActionLoading(true) - await AccountServiceClient.accountLoginClicked({}) - .catch(() => {}) - .finally(() => setIsActionLoading(false)) - await finishOnboarding(true, stepNumber + 1) + await loginAndFinishOnboarding(true, stepNumber + 1) break case "next": StateServiceClient.captureOnboardingProgress({ step: stepNumber + 1 }) @@ -352,13 +394,11 @@ const OnboardingViewContent = ({ onboardingModels }: { onboardingModels: Onboard setStepNumber(stepNumber - 1) break case "done": - await StateServiceClient.setWelcomeViewCompleted({ value: true }).catch(() => {}) - setShowWelcome(false) await finishOnboarding(false, stepNumber) break } }, - [stepNumber, finishOnboarding, setShowWelcome], + [stepNumber, finishOnboarding, loginAndFinishOnboarding], ) const stepDisplayInfo = useMemo(() => { @@ -398,16 +438,27 @@ const OnboardingViewContent = ({ onboardingModels }: { onboardingModels: Onboard