Skip to content

Commit ea35909

Browse files
authored
Merge branch 'main' into roo_provider_on_welcome
2 parents 376c8f1 + ab0644d commit ea35909

File tree

5 files changed

+105
-6
lines changed

5 files changed

+105
-6
lines changed

packages/types/src/telemetry.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export enum TelemetryEventName {
6363

6464
FEATURED_PROVIDER_CLICKED = "Featured Provider Clicked",
6565

66+
UPSELL_DISMISSED = "Upsell Dismissed",
67+
UPSELL_CLICKED = "Upsell Clicked",
68+
6669
SCHEMA_VALIDATION_ERROR = "Schema Validation Error",
6770
DIFF_APPLICATION_ERROR = "Diff Application Error",
6871
SHELL_INTEGRATION_ERROR = "Shell Integration Error",
@@ -184,6 +187,8 @@ export const rooCodeTelemetryEventSchema = z.discriminatedUnion("type", [
184187
TelemetryEventName.ACCOUNT_LOGOUT_CLICKED,
185188
TelemetryEventName.ACCOUNT_LOGOUT_SUCCESS,
186189
TelemetryEventName.FEATURED_PROVIDER_CLICKED,
190+
TelemetryEventName.UPSELL_DISMISSED,
191+
TelemetryEventName.UPSELL_CLICKED,
187192
TelemetryEventName.SCHEMA_VALIDATION_ERROR,
188193
TelemetryEventName.DIFF_APPLICATION_ERROR,
189194
TelemetryEventName.SHELL_INTEGRATION_ERROR,

src/core/tools/multiApplyDiffTool.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ Error: ${failPart.error}
463463
Suggested fixes:
464464
1. Verify the search content exactly matches the file content (including whitespace and case)
465465
2. Check for correct indentation and line endings
466-
3. Use <read_file> to see the current file content
466+
3. Use the read_file tool to verify the file's current contents
467467
4. Consider breaking complex changes into smaller diffs
468468
5. Ensure start_line parameter matches the actual content location
469469
${errorDetails ? `\nDetailed error information:\n${errorDetails}\n` : ""}
@@ -476,7 +476,7 @@ Unable to apply diffs to file: ${absolutePath}
476476
Error: ${diffResult.error}
477477
478478
Recovery suggestions:
479-
1. Use <read_file> to examine the current file content
479+
1. Use the read_file tool to verify the file's current contents
480480
2. Verify the diff format matches the expected search/replace pattern
481481
3. Check that the search content exactly matches what's in the file
482482
4. Consider using line numbers with start_line parameter

src/core/webview/ClineProvider.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,6 +2255,18 @@ export class ClineProvider
22552255
return
22562256
}
22572257

2258+
// Log out from cloud if authenticated
2259+
if (CloudService.hasInstance()) {
2260+
try {
2261+
await CloudService.instance.logout()
2262+
} catch (error) {
2263+
this.log(
2264+
`Failed to logout from cloud during reset: ${error instanceof Error ? error.message : String(error)}`,
2265+
)
2266+
// Continue with reset even if logout fails
2267+
}
2268+
}
2269+
22582270
await this.contextProxy.resetAllState()
22592271
await this.providerSettingsManager.resetAllConfigs()
22602272
await this.customModesManager.resetCustomModes()

webview-ui/src/components/common/DismissibleUpsell.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { memo, ReactNode, useEffect, useState, useRef } from "react"
22
import { vscode } from "@src/utils/vscode"
33
import { useAppTranslation } from "@src/i18n/TranslationContext"
4+
import { telemetryClient } from "@src/utils/TelemetryClient"
5+
import { TelemetryEventName } from "@roo-code/types"
46

57
interface DismissibleUpsellProps {
68
/** Required unique identifier for this upsell */
@@ -76,7 +78,12 @@ const DismissibleUpsell = memo(
7678
}
7779
}, [upsellId])
7880

79-
const handleDismiss = async () => {
81+
const handleDismiss = () => {
82+
// Track telemetry for dismissal
83+
telemetryClient.capture(TelemetryEventName.UPSELL_DISMISSED, {
84+
upsellId: upsellId,
85+
})
86+
8087
// First notify the extension to persist the dismissal
8188
// This ensures the message is sent even if the component unmounts quickly
8289
vscode.postMessage({
@@ -134,6 +141,13 @@ const DismissibleUpsell = memo(
134141
<div
135142
className={containerClasses}
136143
onClick={() => {
144+
// Track telemetry for click
145+
if (onClick) {
146+
telemetryClient.capture(TelemetryEventName.UPSELL_CLICKED, {
147+
upsellId: upsellId,
148+
})
149+
}
150+
137151
// Call the onClick handler if provided
138152
onClick?.()
139153
// Also dismiss if dismissOnClick is true

webview-ui/src/components/common/__tests__/DismissibleUpsell.spec.tsx

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react"
22
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
33
import DismissibleUpsell from "../DismissibleUpsell"
4+
import { TelemetryEventName } from "@roo-code/types"
45

56
// Mock the vscode API
67
const mockPostMessage = vi.fn()
@@ -10,6 +11,14 @@ vi.mock("@src/utils/vscode", () => ({
1011
},
1112
}))
1213

14+
// Mock telemetryClient
15+
const mockCapture = vi.fn()
16+
vi.mock("@src/utils/TelemetryClient", () => ({
17+
telemetryClient: {
18+
capture: (eventName: string, properties?: Record<string, any>) => mockCapture(eventName, properties),
19+
},
20+
}))
21+
1322
// Mock the translation hook
1423
vi.mock("@src/i18n/TranslationContext", () => ({
1524
useAppTranslation: () => ({
@@ -26,6 +35,7 @@ vi.mock("@src/i18n/TranslationContext", () => ({
2635
describe("DismissibleUpsell", () => {
2736
beforeEach(() => {
2837
mockPostMessage.mockClear()
38+
mockCapture.mockClear()
2939
vi.clearAllTimers()
3040
})
3141

@@ -72,7 +82,7 @@ describe("DismissibleUpsell", () => {
7282
})
7383
})
7484

75-
it("hides the upsell when dismiss button is clicked", async () => {
85+
it("hides the upsell when dismiss button is clicked and tracks telemetry", async () => {
7686
const onDismiss = vi.fn()
7787
const { container } = render(
7888
<DismissibleUpsell upsellId="test-upsell" onDismiss={onDismiss}>
@@ -92,6 +102,11 @@ describe("DismissibleUpsell", () => {
92102
const dismissButton = screen.getByRole("button", { name: /dismiss/i })
93103
fireEvent.click(dismissButton)
94104

105+
// Check that telemetry was tracked
106+
expect(mockCapture).toHaveBeenCalledWith(TelemetryEventName.UPSELL_DISMISSED, {
107+
upsellId: "test-upsell",
108+
})
109+
95110
// Check that the dismiss message was sent BEFORE hiding
96111
expect(mockPostMessage).toHaveBeenCalledWith({
97112
type: "dismissUpsell",
@@ -351,7 +366,7 @@ describe("DismissibleUpsell", () => {
351366
})
352367
})
353368

354-
it("calls onClick when the container is clicked", async () => {
369+
it("calls onClick when the container is clicked and tracks telemetry", async () => {
355370
const onClick = vi.fn()
356371
render(
357372
<DismissibleUpsell upsellId="test-upsell" onClick={onClick}>
@@ -372,6 +387,11 @@ describe("DismissibleUpsell", () => {
372387
fireEvent.click(container)
373388

374389
expect(onClick).toHaveBeenCalledTimes(1)
390+
391+
// Check that telemetry was tracked
392+
expect(mockCapture).toHaveBeenCalledWith(TelemetryEventName.UPSELL_CLICKED, {
393+
upsellId: "test-upsell",
394+
})
375395
})
376396

377397
it("does not call onClick when dismiss button is clicked", async () => {
@@ -470,7 +490,7 @@ describe("DismissibleUpsell", () => {
470490
})
471491
})
472492

473-
it("dismisses when clicked if dismissOnClick is true", async () => {
493+
it("dismisses when clicked if dismissOnClick is true and tracks both telemetry events", async () => {
474494
const onClick = vi.fn()
475495
const onDismiss = vi.fn()
476496
const { container } = render(
@@ -493,6 +513,14 @@ describe("DismissibleUpsell", () => {
493513
expect(onClick).toHaveBeenCalledTimes(1)
494514
expect(onDismiss).toHaveBeenCalledTimes(1)
495515

516+
// Check that both telemetry events were tracked
517+
expect(mockCapture).toHaveBeenCalledWith(TelemetryEventName.UPSELL_CLICKED, {
518+
upsellId: "test-upsell",
519+
})
520+
expect(mockCapture).toHaveBeenCalledWith(TelemetryEventName.UPSELL_DISMISSED, {
521+
upsellId: "test-upsell",
522+
})
523+
496524
expect(mockPostMessage).toHaveBeenCalledWith({
497525
type: "dismissUpsell",
498526
upsellId: "test-upsell",
@@ -503,6 +531,46 @@ describe("DismissibleUpsell", () => {
503531
})
504532
})
505533

534+
it("dismisses on container click when dismissOnClick is true and no onClick is provided; tracks only dismissal", async () => {
535+
const onDismiss = vi.fn()
536+
const { container } = render(
537+
<DismissibleUpsell upsellId="test-upsell" onDismiss={onDismiss} dismissOnClick={true}>
538+
<div>Test content</div>
539+
</DismissibleUpsell>,
540+
)
541+
542+
// Make component visible
543+
makeUpsellVisible()
544+
545+
// Wait for component to be visible
546+
await waitFor(() => {
547+
expect(screen.getByText("Test content")).toBeInTheDocument()
548+
})
549+
550+
// Click on the container (not the dismiss button)
551+
const containerDiv = screen.getByText("Test content").parentElement as HTMLElement
552+
fireEvent.click(containerDiv)
553+
554+
// onDismiss should be called
555+
expect(onDismiss).toHaveBeenCalledTimes(1)
556+
557+
// Telemetry: only dismissal should be tracked
558+
expect(mockCapture).toHaveBeenCalledWith(TelemetryEventName.UPSELL_DISMISSED, {
559+
upsellId: "test-upsell",
560+
})
561+
expect(mockCapture).not.toHaveBeenCalledWith(TelemetryEventName.UPSELL_CLICKED, expect.anything())
562+
563+
// Dismiss message should be sent
564+
expect(mockPostMessage).toHaveBeenCalledWith({
565+
type: "dismissUpsell",
566+
upsellId: "test-upsell",
567+
})
568+
569+
// Component should be hidden
570+
await waitFor(() => {
571+
expect(container.firstChild).toBeNull()
572+
})
573+
})
506574
it("does not dismiss when clicked if dismissOnClick is false", async () => {
507575
const onClick = vi.fn()
508576
const onDismiss = vi.fn()

0 commit comments

Comments
 (0)