Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 618badd

Browse files
committed
Remove Roo Code Cloud welcome CTAs
1 parent ad25634 commit 618badd

40 files changed

Lines changed: 77 additions & 184 deletions

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo
22
import { useDeepCompareEffect, useEvent } from "react-use"
33
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
44
import removeMd from "remove-markdown"
5-
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
65
import useSound from "use-sound"
76
import { LRUCache } from "lru-cache"
8-
import { Trans } from "react-i18next"
97

108
import { useDebounceEffect } from "@src/utils/useDebounceEffect"
119
import { appendImages } from "@src/utils/imageUtils"
@@ -31,7 +29,6 @@ import { useSelectedModel } from "@src/components/ui/hooks/useSelectedModel"
3129
import RooHero from "@src/components/welcome/RooHero"
3230
import RooTips from "@src/components/welcome/RooTips"
3331
import { StandardTooltip, Button } from "@src/components/ui"
34-
import { CloudUpsellDialog } from "@src/components/cloud/CloudUpsellDialog"
3532

3633
import TelemetryBanner from "../common/TelemetryBanner"
3734
import VersionIndicator from "../common/VersionIndicator"
@@ -46,10 +43,7 @@ import { CheckpointWarning } from "./CheckpointWarning"
4643
import { QueuedMessages } from "./QueuedMessages"
4744
import { WorktreeSelector } from "./WorktreeSelector"
4845
import FileChangesPanel from "./FileChangesPanel"
49-
import DismissibleUpsell from "../common/DismissibleUpsell"
50-
import { useCloudUpsell } from "@src/hooks/useCloudUpsell"
5146
import { useScrollLifecycle } from "@src/hooks/useScrollLifecycle"
52-
import { Cloud } from "lucide-react"
5347

5448
export interface ChatViewProps {
5549
isHidden: boolean
@@ -90,7 +84,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
9084
telemetrySetting,
9185
soundEnabled,
9286
soundVolume,
93-
cloudIsAuthenticated,
9487
messageQueue = [],
9588
showWorktreesInHomeScreen,
9689
} = useExtensionState()
@@ -187,15 +180,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
187180
clineAskRef.current = clineAsk
188181
}, [clineAsk])
189182

190-
const {
191-
isOpen: isUpsellOpen,
192-
openUpsell,
193-
closeUpsell,
194-
handleConnect,
195-
} = useCloudUpsell({
196-
autoOpenOnAuth: false,
197-
})
198-
199183
// Keep inputValueRef in sync with inputValue state
200184
useEffect(() => {
201185
inputValueRef.current = inputValue
@@ -1639,22 +1623,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
16391623
{/* Everyone should see their task history if any */}
16401624
{taskHistory.length > 0 && <HistoryPreview />}
16411625
</div>
1642-
{/* Logged out users should see a one-time upsell, but not for brand new users */}
1643-
{!cloudIsAuthenticated && taskHistory.length >= 6 && (
1644-
<DismissibleUpsell
1645-
upsellId="taskList2"
1646-
icon={<Cloud className="size-5 shrink-0" />}
1647-
onClick={() => openUpsell()}
1648-
dismissOnClick={false}
1649-
className="bg-none mt-6 border-border rounded-xl p-3 !text-base">
1650-
<Trans
1651-
i18nKey="cloud:upsell.taskList"
1652-
components={{
1653-
learnMoreLink: <VSCodeLink href="#" />,
1654-
}}
1655-
/>
1656-
</DismissibleUpsell>
1657-
)}
16581626
</div>
16591627
</div>
16601628
)}
@@ -1825,7 +1793,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
18251793
)}
18261794

18271795
<div id="roo-portal" />
1828-
<CloudUpsellDialog open={isUpsellOpen} onOpenChange={closeUpsell} onConnect={handleConnect} />
18291796
</div>
18301797
)
18311798
}

webview-ui/src/components/chat/__tests__/ChatView.spec.tsx

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,6 @@ vi.mock("../Announcement", () => ({
9898
},
9999
}))
100100

101-
// Mock DismissibleUpsell component
102-
vi.mock("@/components/common/DismissibleUpsell", () => ({
103-
default: function MockDismissibleUpsell({ children }: { children: React.ReactNode }) {
104-
return <div data-testid="dismissible-upsell">{children}</div>
105-
},
106-
}))
107-
108101
// Mock QueuedMessages component
109102
vi.mock("../QueuedMessages", () => ({
110103
QueuedMessages: function MockQueuedMessages({
@@ -670,10 +663,10 @@ describe("ChatView - Version Indicator Tests", () => {
670663
})
671664
})
672665

673-
describe("ChatView - DismissibleUpsell Display Tests", () => {
666+
describe("ChatView - Cloud upsell display tests", () => {
674667
beforeEach(() => vi.clearAllMocks())
675668

676-
it("does not show DismissibleUpsell when user is authenticated to Cloud", () => {
669+
it("does not show Cloud upsell when user is authenticated to Cloud", () => {
677670
const { queryByTestId } = renderChatView()
678671

679672
// Hydrate state with user authenticated to cloud
@@ -688,11 +681,11 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
688681
clineMessages: [], // No active task
689682
})
690683

691-
// Should not show DismissibleUpsell when authenticated
684+
// Should not show Cloud upsell when authenticated
692685
expect(queryByTestId("dismissible-upsell")).not.toBeInTheDocument()
693686
})
694687

695-
it("does not show DismissibleUpsell when user has only run 3 tasks in their history", () => {
688+
it("does not show Cloud upsell when user has only run 3 tasks in their history", () => {
696689
const { queryByTestId } = renderChatView()
697690

698691
// Hydrate state with user not authenticated but only 3 tasks
@@ -706,12 +699,12 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
706699
clineMessages: [], // No active task
707700
})
708701

709-
// Should not show DismissibleUpsell with less than 4 tasks
702+
// Should not show Cloud upsell with less than 4 tasks
710703
expect(queryByTestId("dismissible-upsell")).not.toBeInTheDocument()
711704
})
712705

713-
it("shows DismissibleUpsell when user is not authenticated and has run 6 or more tasks", async () => {
714-
const { getByTestId } = renderChatView()
706+
it("does not show Cloud upsell when user is not authenticated and has run 6 or more tasks", async () => {
707+
const { queryByTestId } = renderChatView()
715708

716709
// Hydrate state with user not authenticated and 4 tasks
717710
mockPostMessage({
@@ -728,13 +721,13 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
728721
clineMessages: [], // No active task
729722
})
730723

731-
// Wait for component to render and show DismissibleUpsell
724+
// The Cloud upsell CTA has been removed from the home screen.
732725
await waitFor(() => {
733-
expect(getByTestId("dismissible-upsell")).toBeInTheDocument()
726+
expect(queryByTestId("dismissible-upsell")).not.toBeInTheDocument()
734727
})
735728
})
736729

737-
it("does not show DismissibleUpsell when there is an active task (regardless of auth status)", async () => {
730+
it("does not show Cloud upsell when there is an active task (regardless of auth status)", async () => {
738731
const { queryByTestId } = renderChatView()
739732

740733
// Hydrate state with active task
@@ -758,7 +751,7 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
758751

759752
// Wait for component to render with active task
760753
await waitFor(() => {
761-
// Should not show DismissibleUpsell during active task
754+
// Should not show Cloud upsell during active task
762755
expect(queryByTestId("dismissible-upsell")).not.toBeInTheDocument()
763756
// Should not show RooTips either since the entire welcome screen is hidden during active tasks
764757
expect(queryByTestId("roo-tips")).not.toBeInTheDocument()
@@ -767,7 +760,7 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
767760
})
768761
})
769762

770-
it("shows RooTips when user is authenticated (instead of DismissibleUpsell)", () => {
763+
it("shows RooTips when user is authenticated", () => {
771764
const { queryByTestId, getByTestId } = renderChatView()
772765

773766
// Hydrate state with user authenticated to cloud
@@ -782,12 +775,12 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
782775
clineMessages: [], // No active task
783776
})
784777

785-
// Should not show DismissibleUpsell but should show RooTips
778+
// Should not show Cloud upsell but should show RooTips
786779
expect(queryByTestId("dismissible-upsell")).not.toBeInTheDocument()
787780
expect(getByTestId("roo-tips")).toBeInTheDocument()
788781
})
789782

790-
it("shows RooTips when user has fewer than 6 tasks (instead of DismissibleUpsell)", () => {
783+
it("shows RooTips when user has fewer than 6 tasks", () => {
791784
const { queryByTestId, getByTestId } = renderChatView()
792785

793786
// Hydrate state with user not authenticated but fewer than 4 tasks
@@ -801,7 +794,7 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
801794
clineMessages: [], // No active task
802795
})
803796

804-
// Should not show DismissibleUpsell but should show RooTips
797+
// Should not show Cloud upsell but should show RooTips
805798
expect(queryByTestId("dismissible-upsell")).not.toBeInTheDocument()
806799
expect(getByTestId("roo-tips")).toBeInTheDocument()
807800
})

webview-ui/src/components/welcome/WelcomeViewProvider.tsx

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,8 @@ const WelcomeViewProvider = () => {
9191
)
9292

9393
const handleGetStarted = useCallback(() => {
94-
// Landing screen - always trigger auth with Roo
9594
if (selectedProvider === null) {
96-
setAuthOrigin("landing")
97-
vscode.postMessage({ type: "rooCloudSignIn", useProviderSignup: true })
98-
setAuthInProgress(true)
95+
setSelectedProvider("roo")
9996
}
10097
// Provider Selection screen
10198
else if (selectedProvider === "roo") {
@@ -129,11 +126,6 @@ const WelcomeViewProvider = () => {
129126
}
130127
}, [selectedProvider, cloudIsAuthenticated, apiConfiguration, currentApiConfigName])
131128

132-
const handleNoAccount = useCallback(() => {
133-
// Navigate to Provider Selection, defaulting to Roo option
134-
setSelectedProvider("roo")
135-
}, [])
136-
137129
const handleBackToLanding = useCallback(() => {
138130
// Return to the landing screen
139131
setSelectedProvider(null)
@@ -299,18 +291,12 @@ const WelcomeViewProvider = () => {
299291
<p className="text-base text-vscode-foreground">
300292
<Trans i18nKey="welcome:landing.introduction" />
301293
</p>
302-
<p className="mb-0 font-semibold">
303-
<Trans i18nKey="welcome:landing.accountMention" />
304-
</p>
305294
</div>
306295

307296
<div className="mt-2 flex gap-2 items-center">
308297
<Button onClick={handleGetStarted} variant="primary">
309298
{t("welcome:landing.getStarted")}
310299
</Button>
311-
<VSCodeLink onClick={handleNoAccount} className="cursor-pointer">
312-
{t("welcome:landing.noAccount")}
313-
</VSCodeLink>
314300
</div>
315301

316302
<div className="absolute bottom-6 left-6">

webview-ui/src/components/welcome/__tests__/WelcomeViewProvider.spec.tsx

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -128,67 +128,34 @@ describe("WelcomeViewProvider", () => {
128128
// Should show introduction
129129
expect(screen.getByTestId("trans-welcome:landing.introduction")).toBeInTheDocument()
130130

131-
// Should show account mention
132-
expect(screen.getByTestId("trans-welcome:landing.accountMention")).toBeInTheDocument()
133-
134131
// Should show "Get Started" button
135132
expect(screen.getByTestId("button-primary")).toBeInTheDocument()
136133

137-
// Should show "no account" link
138-
const noAccountLink = screen
139-
.getAllByTestId("vscode-link")
140-
.find((link) => link.textContent?.includes("welcome:landing.noAccount"))
141-
expect(noAccountLink).toBeInTheDocument()
142-
})
143-
144-
it("triggers auth when 'Get Started' is clicked on landing", () => {
145-
renderWelcomeViewProvider()
146-
147-
const getStartedButton = screen.getByTestId("button-primary")
148-
fireEvent.click(getStartedButton)
149-
150-
expect(vscode.postMessage).toHaveBeenCalledWith({
151-
type: "rooCloudSignIn",
152-
useProviderSignup: true,
153-
})
134+
// Should not show Cloud account CTA copy
135+
expect(screen.queryByTestId("trans-welcome:landing.accountMention")).not.toBeInTheDocument()
154136
})
155137

156-
it("shows auth in progress after clicking 'Get Started' on landing", () => {
138+
it("navigates to provider selection when 'Get Started' is clicked on landing", () => {
157139
renderWelcomeViewProvider()
158140

159141
const getStartedButton = screen.getByTestId("button-primary")
160142
fireEvent.click(getStartedButton)
161143

162-
// Should show progress ring
163-
expect(screen.getByTestId("progress-ring")).toBeInTheDocument()
164-
165-
// Should show waiting heading
166-
expect(screen.getByText(/welcome:waitingForCloud.heading/)).toBeInTheDocument()
167-
})
168-
169-
it("navigates to provider selection when 'no account' is clicked", () => {
170-
renderWelcomeViewProvider()
171-
172-
// Click the "no account" link
173-
const noAccountLink = screen
174-
.getAllByTestId("vscode-link")
175-
.find((link) => link.textContent?.includes("welcome:landing.noAccount"))
176-
fireEvent.click(noAccountLink!)
177-
178-
// Should now show provider selection screen with radio buttons
179144
expect(screen.getByTestId("radio-group")).toBeInTheDocument()
180145
expect(screen.getByTestId("radio-roo")).toBeInTheDocument()
181146
expect(screen.getByTestId("radio-custom")).toBeInTheDocument()
182147
expect(screen.getByTestId("trans-welcome:providerSignup.chooseProvider")).toBeInTheDocument()
148+
expect(vscode.postMessage).not.toHaveBeenCalledWith({
149+
type: "rooCloudSignIn",
150+
useProviderSignup: true,
151+
})
183152
})
184153
})
185154

186155
describe("Provider Selection Screen", () => {
187156
const navigateToProviderSelection = () => {
188-
const noAccountLink = screen
189-
.getAllByTestId("vscode-link")
190-
.find((link) => link.textContent?.includes("welcome:landing.noAccount"))
191-
fireEvent.click(noAccountLink!)
157+
const getStartedButton = screen.getByTestId("button-primary")
158+
fireEvent.click(getStartedButton)
192159
}
193160

194161
it("shows radio buttons for Roo and Custom providers", () => {
@@ -275,11 +242,18 @@ describe("WelcomeViewProvider", () => {
275242
})
276243

277244
describe("Auth In Progress State", () => {
245+
const startProviderAuth = () => {
246+
const landingGetStartedButton = screen.getByTestId("button-primary")
247+
fireEvent.click(landingGetStartedButton)
248+
249+
const providerGetStartedButton = screen.getByTestId("button-primary")
250+
fireEvent.click(providerGetStartedButton)
251+
}
252+
278253
it("shows waiting state with progress ring", () => {
279254
renderWelcomeViewProvider()
280255

281-
const getStartedButton = screen.getByTestId("button-primary")
282-
fireEvent.click(getStartedButton)
256+
startProviderAuth()
283257

284258
// Should show progress ring
285259
expect(screen.getByTestId("progress-ring")).toBeInTheDocument()
@@ -294,42 +268,33 @@ describe("WelcomeViewProvider", () => {
294268
it("shows Go Back button in waiting state", () => {
295269
renderWelcomeViewProvider()
296270

297-
const getStartedButton = screen.getByTestId("button-primary")
298-
fireEvent.click(getStartedButton)
271+
startProviderAuth()
299272

300273
// Should show secondary button (Go Back)
301274
expect(screen.getByTestId("button-secondary")).toBeInTheDocument()
302275
expect(screen.getByText(/welcome:waitingForCloud.goBack/)).toBeInTheDocument()
303276
})
304277

305-
it("returns to landing screen when Go Back is clicked (auth from landing)", () => {
278+
it("returns to provider selection when Go Back is clicked", () => {
306279
renderWelcomeViewProvider()
307280

308-
// Start auth from landing
309-
const getStartedButton = screen.getByTestId("button-primary")
310-
fireEvent.click(getStartedButton)
311-
312-
// Verify we're in auth progress
313-
expect(screen.getByTestId("progress-ring")).toBeInTheDocument()
281+
startProviderAuth()
314282

315283
// Click Go Back
316284
const goBackButton = screen.getByTestId("button-secondary")
317285
fireEvent.click(goBackButton)
318286

319-
// Should be back on landing screen
320-
expect(screen.getByText(/welcome:landing.greeting/)).toBeInTheDocument()
321-
expect(screen.getByTestId("trans-welcome:landing.introduction")).toBeInTheDocument()
287+
// Should be back on provider selection screen
288+
expect(screen.getByTestId("radio-group")).toBeInTheDocument()
322289
expect(screen.queryByTestId("progress-ring")).not.toBeInTheDocument()
323290
})
324291

325292
it("returns to provider selection when Go Back is clicked (auth from provider selection)", () => {
326293
renderWelcomeViewProvider({ cloudIsAuthenticated: false })
327294

328295
// Navigate to provider selection
329-
const noAccountLink = screen
330-
.getAllByTestId("vscode-link")
331-
.find((link) => link.textContent?.includes("welcome:landing.noAccount"))
332-
fireEvent.click(noAccountLink!)
296+
const landingGetStartedButton = screen.getByTestId("button-primary")
297+
fireEvent.click(landingGetStartedButton)
333298

334299
// Start auth from provider selection (Roo is selected by default)
335300
const getStartedButton = screen.getByTestId("button-primary")

0 commit comments

Comments
 (0)