Browse Source

Revert "feat: Experiment: Show a bit of stats in Cloud tab to help users discover there's more in Cloud" (#8559)

Matt Rubens 2 months ago
parent
commit
eeaafef786
48 changed files with 142 additions and 691 deletions
  1. 7 29
      packages/cloud/src/CloudAPI.ts
  2. 0 63
      src/core/webview/webviewMessageHandler.ts
  3. 0 2
      src/shared/ExtensionMessage.ts
  4. 0 1
      src/shared/WebviewMessage.ts
  5. 6 2
      webview-ui/src/__tests__/ContextWindowProgress.spec.tsx
  6. 3 13
      webview-ui/src/components/chat/ChatRow.tsx
  7. 1 3
      webview-ui/src/components/chat/ContextWindowProgress.tsx
  8. 3 17
      webview-ui/src/components/chat/TaskHeader.tsx
  9. 0 9
      webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx
  10. 104 122
      webview-ui/src/components/cloud/CloudView.tsx
  11. 0 183
      webview-ui/src/components/cloud/UsagePreview.tsx
  12. 1 2
      webview-ui/src/i18n/locales/ca/chat.json
  13. 0 11
      webview-ui/src/i18n/locales/ca/cloud.json
  14. 1 2
      webview-ui/src/i18n/locales/de/chat.json
  15. 0 11
      webview-ui/src/i18n/locales/de/cloud.json
  16. 1 2
      webview-ui/src/i18n/locales/en/chat.json
  17. 0 11
      webview-ui/src/i18n/locales/en/cloud.json
  18. 1 2
      webview-ui/src/i18n/locales/es/chat.json
  19. 0 11
      webview-ui/src/i18n/locales/es/cloud.json
  20. 1 2
      webview-ui/src/i18n/locales/fr/chat.json
  21. 0 11
      webview-ui/src/i18n/locales/fr/cloud.json
  22. 1 2
      webview-ui/src/i18n/locales/hi/chat.json
  23. 0 11
      webview-ui/src/i18n/locales/hi/cloud.json
  24. 1 2
      webview-ui/src/i18n/locales/id/chat.json
  25. 0 11
      webview-ui/src/i18n/locales/id/cloud.json
  26. 1 2
      webview-ui/src/i18n/locales/it/chat.json
  27. 0 11
      webview-ui/src/i18n/locales/it/cloud.json
  28. 1 2
      webview-ui/src/i18n/locales/ja/chat.json
  29. 0 11
      webview-ui/src/i18n/locales/ja/cloud.json
  30. 1 2
      webview-ui/src/i18n/locales/ko/chat.json
  31. 0 11
      webview-ui/src/i18n/locales/ko/cloud.json
  32. 1 2
      webview-ui/src/i18n/locales/nl/chat.json
  33. 0 11
      webview-ui/src/i18n/locales/nl/cloud.json
  34. 1 2
      webview-ui/src/i18n/locales/pl/chat.json
  35. 0 11
      webview-ui/src/i18n/locales/pl/cloud.json
  36. 1 2
      webview-ui/src/i18n/locales/pt-BR/chat.json
  37. 0 11
      webview-ui/src/i18n/locales/pt-BR/cloud.json
  38. 1 2
      webview-ui/src/i18n/locales/ru/chat.json
  39. 0 11
      webview-ui/src/i18n/locales/ru/cloud.json
  40. 1 2
      webview-ui/src/i18n/locales/tr/chat.json
  41. 0 11
      webview-ui/src/i18n/locales/tr/cloud.json
  42. 1 2
      webview-ui/src/i18n/locales/vi/chat.json
  43. 0 11
      webview-ui/src/i18n/locales/vi/cloud.json
  44. 1 2
      webview-ui/src/i18n/locales/zh-CN/chat.json
  45. 0 11
      webview-ui/src/i18n/locales/zh-CN/cloud.json
  46. 1 2
      webview-ui/src/i18n/locales/zh-TW/chat.json
  47. 0 11
      webview-ui/src/i18n/locales/zh-TW/cloud.json
  48. 0 13
      webview-ui/src/utils/format.ts

+ 7 - 29
packages/cloud/src/CloudAPI.ts

@@ -1,13 +1,6 @@
 import { z } from "zod"
 
-import {
-	type AuthService,
-	type ShareVisibility,
-	type ShareResponse,
-	shareResponseSchema,
-	type UsageStats,
-	usageStatsSchema,
-} from "@roo-code/types"
+import { type AuthService, type ShareVisibility, type ShareResponse, shareResponseSchema } from "@roo-code/types"
 
 import { getRooCodeApiUrl } from "./config.js"
 import { getUserAgent } from "./utils.js"
@@ -60,11 +53,9 @@ export class CloudAPI {
 			})
 
 			if (!response.ok) {
-				this.log(`[CloudAPI] Request to ${endpoint} failed with status ${response.status}`)
 				await this.handleErrorResponse(response, endpoint)
 			}
 
-			// Log before attempting to read the body
 			const data = await response.json()
 
 			if (parseResponse) {
@@ -95,15 +86,9 @@ export class CloudAPI {
 		let responseBody: unknown
 
 		try {
-			const bodyText = await response.text()
-
-			try {
-				responseBody = JSON.parse(bodyText)
-			} catch {
-				responseBody = bodyText
-			}
-		} catch (_error) {
-			responseBody = "Failed to read error response"
+			responseBody = await response.json()
+		} catch {
+			responseBody = await response.text()
 		}
 
 		switch (response.status) {
@@ -124,12 +109,15 @@ export class CloudAPI {
 	}
 
 	async shareTask(taskId: string, visibility: ShareVisibility = "organization"): Promise<ShareResponse> {
+		this.log(`[CloudAPI] Sharing task ${taskId} with visibility: ${visibility}`)
+
 		const response = await this.request("/api/extension/share", {
 			method: "POST",
 			body: JSON.stringify({ taskId, visibility }),
 			parseResponse: (data) => shareResponseSchema.parse(data),
 		})
 
+		this.log("[CloudAPI] Share response:", response)
 		return response
 	}
 
@@ -146,14 +134,4 @@ export class CloudAPI {
 					.parse(data),
 		})
 	}
-
-	async getUsagePreview(): Promise<UsageStats> {
-		const response = await this.request("/api/analytics/usage/daily?period=7", {
-			method: "GET",
-			parseResponse: (data) => {
-				return usageStatsSchema.parse(data)
-			},
-		})
-		return response
-	}
 }

+ 0 - 63
src/core/webview/webviewMessageHandler.ts

@@ -3110,68 +3110,5 @@ export const webviewMessageHandler = async (
 			})
 			break
 		}
-		case "getUsagePreview": {
-			try {
-				// Get the CloudAPI instance and fetch usage preview
-				const cloudApi = CloudService.instance.cloudAPI
-				if (!cloudApi) {
-					// User is not authenticated
-					provider.log("[webviewMessageHandler] User not authenticated for usage preview")
-					await provider.postMessageToWebview({
-						type: "usagePreviewData",
-						error: "Authentication required",
-						data: null,
-					})
-					break
-				}
-
-				// Fetch usage preview data
-				const rawUsageData = await cloudApi.getUsagePreview()
-
-				// Transform the data to match UI expectations
-				// The API returns data with separate arrays, but UI expects an array of day objects
-				const dates = rawUsageData.data?.dates ?? []
-				const tasks = rawUsageData.data?.tasks ?? []
-				const tokens = rawUsageData.data?.tokens ?? []
-				const costs = rawUsageData.data?.costs ?? []
-				const len = Math.min(dates.length, tasks.length, tokens.length, costs.length)
-
-				const transformedData = {
-					days: Array.from({ length: len }).map((_, index) => ({
-						date: dates[index] ?? "",
-						taskCount: tasks[index] ?? 0,
-						tokenCount: tokens[index] ?? 0,
-						cost: costs[index] ?? 0,
-					})),
-					totals: rawUsageData.data?.totals || {
-						tasks: 0,
-						tokens: 0,
-						cost: 0,
-					},
-				}
-
-				// Send the transformed data back to the webview
-				await provider.postMessageToWebview({
-					type: "usagePreviewData",
-					data: transformedData,
-					error: undefined,
-				})
-			} catch (error) {
-				provider.log(
-					`[webviewMessageHandler] Failed to fetch usage preview: ${error instanceof Error ? error.message : String(error)}`,
-				)
-				provider.log(
-					`[webviewMessageHandler] Error stack trace: ${error instanceof Error ? error.stack : "No stack trace"}`,
-				)
-
-				// Send error back to webview
-				await provider.postMessageToWebview({
-					type: "usagePreviewData",
-					error: error instanceof Error ? error.message : "Failed to load usage data",
-					data: null,
-				})
-			}
-			break
-		}
 	}
 }

+ 0 - 2
src/shared/ExtensionMessage.ts

@@ -126,7 +126,6 @@ export interface ExtensionMessage {
 		| "insertTextIntoTextarea"
 		| "dismissedUpsells"
 		| "organizationSwitchResult"
-		| "usagePreviewData"
 	text?: string
 	payload?: any // Add a generic payload for now, can refine later
 	action?:
@@ -206,7 +205,6 @@ export interface ExtensionMessage {
 	queuedMessages?: QueuedMessage[]
 	list?: string[] // For dismissedUpsells
 	organizationId?: string | null // For organizationSwitchResult
-	data?: any // For usagePreviewData
 }
 
 export type ExtensionState = Pick<

+ 0 - 1
src/shared/WebviewMessage.ts

@@ -229,7 +229,6 @@ export interface WebviewMessage {
 		| "editQueuedMessage"
 		| "dismissUpsell"
 		| "getDismissedUpsells"
-		| "getUsagePreview"
 	text?: string
 	editedMessageContent?: string
 	tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud"

+ 6 - 2
webview-ui/src/__tests__/ContextWindowProgress.spec.tsx

@@ -8,7 +8,6 @@ import TaskHeader from "@src/components/chat/TaskHeader"
 // Mock formatLargeNumber function
 vi.mock("@/utils/format", () => ({
 	formatLargeNumber: vi.fn((num) => num.toString()),
-	formatCost: (cost: number) => `$${cost.toFixed(2)}`,
 }))
 
 // Mock VSCodeBadge component for all tests
@@ -129,7 +128,12 @@ describe("ContextWindowProgress", () => {
 		expect(windowSize).toBeInTheDocument()
 		expect(windowSize).toHaveTextContent("4000")
 
-		const progressBarContainer = screen.getByTestId("context-progress-bar-container").parentElement
+		// The progress bar is now wrapped in tooltips, but we can verify the structure exists
+		// by checking for the progress bar container
+		const progressBarContainer = screen.getByTestId("context-tokens-count").parentElement
 		expect(progressBarContainer).toBeInTheDocument()
+
+		// Verify the flex container has the expected structure
+		expect(progressBarContainer?.querySelector(".flex-1.relative")).toBeInTheDocument()
 	})
 })

+ 3 - 13
webview-ui/src/components/chat/ChatRow.tsx

@@ -132,8 +132,7 @@ export const ChatRowContent = ({
 }: ChatRowContentProps) => {
 	const { t } = useTranslation()
 
-	const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode, apiConfiguration, cloudIsAuthenticated } =
-		useExtensionState()
+	const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode, apiConfiguration } = useExtensionState()
 	const { info: model } = useSelectedModel(apiConfiguration)
 	const [isEditing, setIsEditing] = useState(false)
 	const [editedContent, setEditedContent] = useState("")
@@ -1075,17 +1074,8 @@ export const ChatRowContent = ({
 									{title}
 								</div>
 								<div
-									className={cn(
-										"text-xs text-vscode-dropdown-foreground border-vscode-dropdown-border/50 border px-1.5 py-0.5 rounded-lg",
-										cloudIsAuthenticated &&
-											"cursor-pointer hover:bg-vscode-dropdown-background hover:border-vscode-dropdown-border transition-colors",
-									)}
-									style={{ opacity: cost !== null && cost !== undefined && cost > 0 ? 1 : 0 }}
-									onClick={(e) => {
-										e.stopPropagation() // Prevent parent onClick from firing
-										vscode.postMessage({ type: "switchTab", tab: "cloud" })
-									}}
-									title={t("chat:apiRequest.viewTokenUsage")}>
+									className="text-xs text-vscode-dropdown-foreground border-vscode-dropdown-border/50 border px-1.5 py-0.5 rounded-lg"
+									style={{ opacity: cost !== null && cost !== undefined && cost > 0 ? 1 : 0 }}>
 									${Number(cost || 0)?.toFixed(4)}
 								</div>
 							</div>

+ 1 - 3
webview-ui/src/components/chat/ContextWindowProgress.tsx

@@ -60,9 +60,7 @@ export const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens
 				<StandardTooltip content={tooltipContent} side="top" sideOffset={8}>
 					<div className="flex-1 relative">
 						{/* Main progress bar container */}
-						<div
-							data-testid="context-progress-bar-container"
-							className="flex items-center h-1 rounded-[2px] overflow-hidden w-full bg-[color-mix(in_srgb,var(--vscode-foreground)_20%,transparent)]">
+						<div className="flex items-center h-1 rounded-[2px] overflow-hidden w-full bg-[color-mix(in_srgb,var(--vscode-foreground)_20%,transparent)]">
 							{/* Current tokens container */}
 							<div
 								className="relative h-full"

+ 3 - 17
webview-ui/src/components/chat/TaskHeader.tsx

@@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next"
 import { useCloudUpsell } from "@src/hooks/useCloudUpsell"
 import { CloudUpsellDialog } from "@src/components/cloud/CloudUpsellDialog"
 import DismissibleUpsell from "@src/components/common/DismissibleUpsell"
-import { FoldVertical, ChevronUp, ChevronDown, ChartColumn } from "lucide-react"
+import { FoldVertical, ChevronUp, ChevronDown } from "lucide-react"
 import prettyBytes from "pretty-bytes"
 
 import type { ClineMessage } from "@roo-code/types"
@@ -11,7 +11,7 @@ import type { ClineMessage } from "@roo-code/types"
 import { getModelMaxOutputTokens } from "@roo/api"
 import { findLastIndex } from "@roo/array"
 
-import { formatCost, formatLargeNumber } from "@src/utils/format"
+import { formatLargeNumber } from "@src/utils/format"
 import { cn } from "@src/lib/utils"
 import { StandardTooltip } from "@src/components/ui"
 import { useExtensionState } from "@src/context/ExtensionStateContext"
@@ -24,8 +24,6 @@ import { ContextWindowProgress } from "./ContextWindowProgress"
 import { Mention } from "./Mention"
 import { TodoListDisplay } from "./TodoListDisplay"
 
-import { vscode } from "@src/utils/vscode"
-
 export interface TaskHeaderProps {
 	task: ClineMessage
 	tokensIn: number
@@ -303,19 +301,7 @@ const TaskHeader = ({
 												{t("chat:task.apiCost")}
 											</th>
 											<td className="align-top">
-												<span>{formatCost(totalCost)}</span>
-												<StandardTooltip content={t("chat:apiRequest.viewTokenUsage")}>
-													<ChartColumn
-														className="inline size-3.5 -mt-0.5 ml-2 text-vscode-textLink-foreground cursor-pointer hover:text-vscode-textLink-activeForeground transition-colors"
-														onClick={(e) => {
-															e.stopPropagation()
-															vscode.postMessage({
-																type: "switchTab",
-																tab: "cloud",
-															})
-														}}
-													/>
-												</StandardTooltip>
+												<span>${totalCost?.toFixed(2)}</span>
 											</td>
 										</tr>
 									)}

+ 0 - 9
webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx

@@ -88,15 +88,6 @@ vi.mock("@roo/array", () => ({
 	},
 }))
 
-// Mock the format utilities
-vi.mock("@/utils/format", async (importOriginal) => {
-	const actual = await importOriginal<typeof import("@/utils/format")>()
-	return {
-		...actual,
-		formatCost: (cost: number) => `$${cost.toFixed(2)}`,
-	}
-})
-
 describe("TaskHeader", () => {
 	const defaultProps: TaskHeaderProps = {
 		task: { type: "say", ts: Date.now(), text: "Test task", images: [] },

+ 104 - 122
webview-ui/src/components/cloud/CloudView.tsx

@@ -9,13 +9,12 @@ import { vscode } from "@src/utils/vscode"
 import { telemetryClient } from "@src/utils/TelemetryClient"
 import { ToggleSwitch } from "@/components/ui/toggle-switch"
 import { renderCloudBenefitsContent } from "./CloudUpsellDialog"
-import { CircleAlert, Lock, TriangleAlert } from "lucide-react"
+import { CircleAlert, Info, Lock, TriangleAlert } from "lucide-react"
 import { cn } from "@/lib/utils"
 import { Tab, TabContent, TabHeader } from "../common/Tab"
 import { Button } from "@/components/ui/button"
 import { OrganizationSwitcher } from "./OrganizationSwitcher"
 import { StandardTooltip } from "../ui"
-import { UsagePreview } from "./UsagePreview"
 
 // Define the production URL constant locally to avoid importing from cloud package in tests
 const PRODUCTION_ROO_CODE_API_URL = "https://app.roocode.com"
@@ -146,14 +145,6 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone, orga
 		}
 	}
 
-	const handleViewUsageStats = () => {
-		const baseUrl = cloudApiUrl || PRODUCTION_ROO_CODE_API_URL
-		vscode.postMessage({
-			type: "openExternal",
-			url: `${baseUrl}/usage?utm_source=extension&utm_medium=stats_preview&utm_campaign=stats_preview`,
-		})
-	}
-
 	const handleRemoteControlToggle = () => {
 		const newValue = !remoteControlEnabled
 		setRemoteControlEnabled(newValue)
@@ -173,128 +164,119 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone, orga
 				<Button onClick={onDone}>{t("settings:common.done")}</Button>
 			</TabHeader>
 
-			<TabContent className="flex flex-col justify-between min-h-full">
+			<TabContent className="pt-10">
 				{isAuthenticated ? (
-					<div className="flex flex-col h-full">
-						{/* Content that scrolls */}
-						<div className="">
-							{userInfo && (
-								<div className="flex items-start gap-4 ml-4 mb-6 flex-col min-[300px]:flex-row">
-									{/* Avatar */}
-									<div className="w-12 h-12 rounded-full overflow-hidden flex-shrink-0">
-										{userInfo?.picture ? (
-											<img
-												src={userInfo.picture}
-												alt={t("cloud:profilePicture")}
-												className="w-full h-full object-cover"
-											/>
-										) : (
-											<div className="w-full h-full flex items-center justify-center bg-vscode-button-background text-vscode-button-foreground text-xl">
-												{userInfo?.name?.charAt(0) || userInfo?.email?.charAt(0) || "?"}
-											</div>
-										)}
-									</div>
-
-									{/* Name, email and org switcher */}
-									<div className="flex flex-col">
-										{userInfo.name && (
-											<h2 className="text-lg font-medium text-vscode-foreground my-0">
-												{userInfo.name}
-											</h2>
-										)}
-										{userInfo?.email && (
-											<p className="text-sm text-vscode-descriptionForeground my-0 mb-2">
-												{userInfo?.email}
-											</p>
-										)}
-
-										{/* Organization Switcher */}
-										<div className="max-w-60">
-											<OrganizationSwitcher
-												userInfo={userInfo}
-												organizations={organizations}
-												cloudApiUrl={cloudApiUrl}
-											/>
+					<>
+						{userInfo && (
+							<div className="flex flex-col items-start ml-4 mb-6">
+								<div className="w-16 h-16 mb-3 rounded-full overflow-hidden">
+									{userInfo?.picture ? (
+										<img
+											src={userInfo.picture}
+											alt={t("cloud:profilePicture")}
+											className="w-full h-full object-cover"
+										/>
+									) : (
+										<div className="w-full h-full flex items-center justify-center bg-vscode-button-background text-vscode-button-foreground text-xl">
+											{userInfo?.name?.charAt(0) || userInfo?.email?.charAt(0) || "?"}
 										</div>
-									</div>
+									)}
 								</div>
-							)}
+								{userInfo.name && (
+									<h2 className="text-lg font-medium text-vscode-foreground my-0">{userInfo.name}</h2>
+								)}
+								{userInfo?.email && (
+									<p className="text-sm text-vscode-descriptionForeground my-0">{userInfo?.email}</p>
+								)}
 
-							{/* Task Sync Toggle - Always shown when authenticated */}
-							<div className="mt-4 p-4 border-b border-t border-vscode-panel-border pl-4 max-w-140">
-								<div className="flex items-center gap-3">
-									<ToggleSwitch
-										checked={taskSyncEnabled}
-										onChange={handleTaskSyncToggle}
-										size="medium"
-										aria-label={t("cloud:taskSync")}
-										data-testid="task-sync-toggle"
-										disabled={!!userInfo?.organizationId}
+								{/* Organization Switcher - moved below email */}
+								<div className="w-full max-w-60 mt-4">
+									<OrganizationSwitcher
+										userInfo={userInfo}
+										organizations={organizations}
+										cloudApiUrl={cloudApiUrl}
 									/>
-									<span className="font-medium text-vscode-foreground flex items-center">
-										{t("cloud:taskSync")}
-										{userInfo?.organizationId && (
-											<StandardTooltip content={t("cloud:taskSyncManagedByOrganization")}>
-												<div className="bg-vscode-badge-background text-vscode-badge-foreground/80 p-1.5 ml-2 -mb-2 relative -top-1 rounded-full inline-block cursor-help">
-													<Lock className="size-3 block" />
-												</div>
-											</StandardTooltip>
-										)}
-									</span>
 								</div>
-								<div className="text-vscode-descriptionForeground text-sm mt-1 ml-8">
-									{t("cloud:taskSyncDescription")}
-								</div>
-
-								{/* Remote Control Toggle - Only shown when both extensionBridgeEnabled and featureRoomoteControlEnabled are true */}
-								{userInfo?.extensionBridgeEnabled && featureRoomoteControlEnabled && (
-									<>
-										<div className="flex items-center gap-3 mt-4">
-											<ToggleSwitch
-												checked={remoteControlEnabled}
-												onChange={handleRemoteControlToggle}
-												size="medium"
-												aria-label={t("cloud:remoteControl")}
-												data-testid="remote-control-toggle"
-												disabled={!taskSyncEnabled}
-											/>
-											<span className="font-medium text-vscode-foreground">
-												{t("cloud:remoteControl")}
-											</span>
-										</div>
-										<div className="text-vscode-descriptionForeground text-sm mt-1 mb-2 ml-8">
-											{t("cloud:remoteControlDescription")}
-											{!taskSyncEnabled && (
-												<div className="text-vscode-editorWarning-foreground mt-2">
-													<CircleAlert className="inline size-3 mr-1 mb-0.5 text-vscode-editorWarning-foreground" />
-													{t("cloud:remoteControlRequiresTaskSync")}
-												</div>
-											)}
-										</div>
-									</>
-								)}
 							</div>
-
-							{/* Usage Stats Chart Section */}
-							<div className="mt-4 mb-4 px-4">
-								<UsagePreview onViewDetails={handleViewUsageStats} />
+						)}
+
+						{/* Task Sync Toggle - Always shown when authenticated */}
+						<div className="mt-4 p-4 border-b border-t border-vscode-widget-border pl-4 max-w-140">
+							<div className="flex items-center gap-3 mb-2">
+								<ToggleSwitch
+									checked={taskSyncEnabled}
+									onChange={handleTaskSyncToggle}
+									size="medium"
+									aria-label={t("cloud:taskSync")}
+									data-testid="task-sync-toggle"
+									disabled={!!userInfo?.organizationId}
+								/>
+								<span className="font-medium text-vscode-foreground flex items-center">
+									{t("cloud:taskSync")}
+									{userInfo?.organizationId && (
+										<StandardTooltip content={t("cloud:taskSyncManagedByOrganization")}>
+											<div className="bg-vscode-badge-background text-vscode-badge-foreground/80 p-1.5 ml-2 -mb-2 relative -top-1 rounded-full inline-block cursor-help">
+												<Lock className="size-3 block" />
+											</div>
+										</StandardTooltip>
+									)}
+								</span>
 							</div>
-
-							<div className="flex flex-col gap-2 mt-4 px-4">
-								<VSCodeButton
-									appearance="secondary"
-									onClick={handleVisitCloudWebsite}
-									className="w-full">
-									{t("cloud:visitCloudWebsite")}
-								</VSCodeButton>
-								<VSCodeButton appearance="secondary" onClick={handleLogoutClick} className="w-full">
-									{t("cloud:logOut")}
-								</VSCodeButton>
+							<div className="text-vscode-descriptionForeground text-sm mt-1 ml-8">
+								{t("cloud:taskSyncDescription")}
 							</div>
+
+							{/* Remote Control Toggle - Only shown when both extensionBridgeEnabled and featureRoomoteControlEnabled are true */}
+							{userInfo?.extensionBridgeEnabled && featureRoomoteControlEnabled && (
+								<>
+									<div className="flex items-center gap-3 mt-4 mb-2">
+										<ToggleSwitch
+											checked={remoteControlEnabled}
+											onChange={handleRemoteControlToggle}
+											size="medium"
+											aria-label={t("cloud:remoteControl")}
+											data-testid="remote-control-toggle"
+											disabled={!taskSyncEnabled}
+										/>
+										<span className="font-medium text-vscode-foreground">
+											{t("cloud:remoteControl")}
+										</span>
+									</div>
+									<div className="text-vscode-descriptionForeground text-sm mt-1 mb-2 ml-8">
+										{t("cloud:remoteControlDescription")}
+										{!taskSyncEnabled && (
+											<div className="text-vscode-editorWarning-foreground mt-2">
+												<CircleAlert className="inline size-3 mr-1 mb-0.5 text-vscode-editorWarning-foreground" />
+												{t("cloud:remoteControlRequiresTaskSync")}
+											</div>
+										)}
+									</div>
+								</>
+							)}
 						</div>
-					</div>
+
+						<div className="text-vscode-descriptionForeground text-sm mt-4 mb-8 pl-4">
+							<Info className="inline size-3 mr-1 mb-0.5 text-vscode-descriptionForeground" />
+							{t("cloud:usageMetricsAlwaysReported")}
+						</div>
+
+						<div className="flex flex-col gap-2 mt-4 pl-4">
+							<VSCodeButton
+								appearance="secondary"
+								onClick={handleVisitCloudWebsite}
+								className="w-full max-w-80">
+								{t("cloud:visitCloudWebsite")}
+							</VSCodeButton>
+							<VSCodeButton
+								appearance="secondary"
+								onClick={handleLogoutClick}
+								className="w-full max-w-80">
+								{t("cloud:logOut")}
+							</VSCodeButton>
+						</div>
+					</>
 				) : (
-					<div>
+					<>
 						<div className="flex flex-col items-start gap-4 px-8 max-w-100">
 							<div className={cn(authInProgress && "opacity-50")}>{renderCloudBenefitsContent(t)}</div>
 
@@ -347,7 +329,7 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone, orga
 								</div>
 							)}
 						</div>
-					</div>
+					</>
 				)}
 				{cloudApiUrl && cloudApiUrl !== PRODUCTION_ROO_CODE_API_URL && (
 					<div className="ml-4 mt-6 flex">

+ 0 - 183
webview-ui/src/components/cloud/UsagePreview.tsx

@@ -1,183 +0,0 @@
-import { useEffect, useState } from "react"
-import { VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
-import { CircleAlert, SquareArrowOutUpRight } from "lucide-react"
-import { useAppTranslation } from "@src/i18n/TranslationContext"
-import { vscode } from "@src/utils/vscode"
-import { formatDateShort, formatLargeNumber, formatCost } from "@/utils/format"
-
-interface DailyUsage {
-	date: string // ISO date string
-	taskCount: number
-	tokenCount: number
-	cost: number // in USD
-}
-
-interface UsageStats {
-	days: DailyUsage[]
-	totals: {
-		tasks: number
-		tokens: number
-		cost: number
-	}
-}
-
-interface UsagePreviewProps {
-	onViewDetails: () => void
-}
-
-export const UsagePreview = ({ onViewDetails }: UsagePreviewProps) => {
-	const { t } = useAppTranslation()
-	const [isLoading, setIsLoading] = useState(true)
-	const [error, setError] = useState<string | null>(null)
-	const [data, setData] = useState<UsageStats | null>(null)
-
-	// Fetch usage data on mount
-	useEffect(() => {
-		setIsLoading(true)
-		setError(null)
-
-		// Request usage preview data from the extension
-		vscode.postMessage({ type: "getUsagePreview" })
-
-		// Listen for the response
-		let timeoutId: ReturnType<typeof setTimeout> | null = null
-		const handleMessage = (event: MessageEvent) => {
-			const message = event.data
-
-			if (message.type === "usagePreviewData") {
-				// Clear timeout on success/error to avoid stale timeout flipping UI into error
-				if (timeoutId) {
-					clearTimeout(timeoutId)
-				}
-
-				if (message.error) {
-					setError(message.error)
-				} else if (message.data) {
-					// Validate the data structure
-					if (!message.data.days || !Array.isArray(message.data.days)) {
-						setError(t("cloud:usagePreview.invalidDataFormat"))
-					} else {
-						setData(message.data)
-					}
-				}
-				setIsLoading(false)
-			}
-		}
-
-		window.addEventListener("message", handleMessage)
-
-		// Clean up listener after 10 seconds (timeout)
-		timeoutId = setTimeout(() => {
-			if (isLoading) {
-				setError(t("cloud:usagePreview.failedToLoad"))
-				setIsLoading(false)
-			}
-		}, 10000)
-
-		return () => {
-			if (timeoutId) {
-				clearTimeout(timeoutId)
-			}
-			window.removeEventListener("message", handleMessage)
-		}
-	}, []) // eslint-disable-line react-hooks/exhaustive-deps
-
-	const getBarHeight = (cost: number): number => {
-		if (!data || !data.days || data.days.length === 0) return 1
-		const maxCost = Math.max(...data.days.map((d) => d.cost))
-		if (!Number.isFinite(maxCost) || maxCost <= 0) return 1
-		// Compute percentage first, then round; enforce minimum height for visibility
-		return Math.max(1, Math.round((cost / maxCost) * 100))
-	}
-
-	// Retry loading
-	const handleRetry = () => {
-		setError(null)
-		setIsLoading(true)
-		vscode.postMessage({ type: "getUsagePreview" })
-	}
-
-	// Loading state
-	if (isLoading) {
-		return (
-			<div
-				className="cursor-pointer group rounded-lg bg-vscode-editor-background hover:bg-vscode-list-hoverBackground transition-colors relative"
-				onClick={onViewDetails}>
-				<div className="p-4">
-					{/* Loading spinner centered in chart area */}
-					<div className="h-20 flex items-center justify-center mb-3">
-						<VSCodeProgressRing className="size-6" />
-					</div>
-				</div>
-			</div>
-		)
-	}
-
-	// Error state
-	if (error || !data) {
-		return (
-			<div
-				className="cursor-pointer group rounded-lg bg-vscode-editor-background hover:bg-vscode-list-hoverBackground transition-colors relative"
-				onClick={handleRetry}>
-				<div className="p-4">
-					{/* Error message in chart area */}
-					<div className="mb-3 text-vscode-descriptionForeground">
-						<CircleAlert className="size-4 mb-2 text-vscode-muted-foreground" />
-						<p className="text-xs font-mono font-bold">{t("cloud:usagePreview.couldNotLoadChart")}</p>
-						<p className="text-xs font-mono">{error}</p>
-						<p className="text-xs font-medium mt-1">{t("cloud:usagePreview.clickToRetry")}</p>
-					</div>
-				</div>
-			</div>
-		)
-	}
-
-	return (
-		<div className="cursor-pointer group rounded-lg bg-vscode-editor-background relative" onClick={onViewDetails}>
-			<div className="p-4">
-				{/* Chart with daily usage bars */}
-				<div
-					className="h-24 min-[450px]:h-40 rounded mb-3 flex items-end gap-1 pb-2"
-					role="img"
-					aria-label={t("cloud:usagePreview.costPastDays", { count: data.days.length })}>
-					{data &&
-						Array.isArray(data.days) &&
-						data.days.map((day, index) => (
-							<div key={index} className="w-full flex flex-col items-center justify-end h-full">
-								<div
-									className="w-full rounded-t-xs transition-all bg-vscode-button-background"
-									style={{ height: `${getBarHeight(day.cost)}%` }}
-									aria-label={`${formatDateShort(new Date(day.date).getTime())}: ${formatCost(day.cost)}`}
-								/>
-								<span className="text-[9px] h-[1em] hidden min-[300px]:block overflow-clip text-center text-muted-foreground mt-0.5">
-									{formatDateShort(new Date(day.date).getTime())}
-								</span>
-							</div>
-						))}
-				</div>
-
-				{/* Stats text */}
-				<div className="flex flex-col justify-between text-sm min-[400px]:flex-row min-[450px]:items-center">
-					<span className="flex items-center gap-1 text-vscode-descriptionForeground">
-						{t("cloud:usagePreview.costPastDays", { count: data.days.length })}
-					</span>
-					<span className="text-vscode-foreground">
-						{t("cloud:usagePreview.tasks", { count: data.totals.tasks })}
-						<span> · </span>
-						{t("cloud:usagePreview.tokens", { count: formatLargeNumber(data.totals.tokens) })}
-						<span> · </span>
-						{formatCost(data.totals.cost)}
-					</span>
-				</div>
-			</div>
-
-			{/* Hover overlay */}
-			<div className="absolute inset-0 bg-vscode-editor-background/85 rounded-lg flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none">
-				<div className="flex items-center gap-2 text-vscode-foreground">
-					<span>{t("cloud:usagePreview.seeMoreStats")}</span>
-					<SquareArrowOutUpRight className="size-3" />
-				</div>
-			</div>
-		</div>
-	)
-}

+ 1 - 2
webview-ui/src/i18n/locales/ca/chat.json

@@ -141,8 +141,7 @@
 		"failed": "Sol·licitud API ha fallat",
 		"streaming": "Sol·licitud API...",
 		"cancelled": "Sol·licitud API cancel·lada",
-		"streamingFailed": "Transmissió API ha fallat",
-		"viewTokenUsage": "Veure les estadístiques d'ús de fitxes"
+		"streamingFailed": "Transmissió API ha fallat"
 	},
 	"checkpoint": {
 		"regular": "Punt de control",

+ 0 - 11
webview-ui/src/i18n/locales/ca/cloud.json

@@ -26,17 +26,6 @@
 	"personalAccount": "Compte Personal",
 	"createTeamAccount": "Crear Compte d'Equip",
 	"switchAccount": "Canviar Compte de Roo Code Cloud",
-	"usagePreview": {
-		"costPastDays": "Cost diari dels darrers {{count}} dies",
-		"seeMoreStats": "Consulta més estadístiques a Roo Code Cloud",
-		"invalidDataFormat": "S'ha rebut un format de dades no vàlid",
-		"failedToLoad": "No s'han pogut carregar les dades d'ús",
-		"couldNotLoadChart": "No s'ha pogut carregar el gràfic:",
-		"clickToRetry": "Fes clic per tornar a intentar-ho",
-		"tasks_one": "{{count}} tasca",
-		"tasks_other": "{{count}} tasques",
-		"tokens": "{{count}} tokens"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Donant-li una mica d'independència a Roo? Controla'l des de qualsevol lloc amb Roo Code Cloud. <learnMoreLink>Més informació</learnMoreLink>.",
 		"longRunningTask": "Això pot trigar una estona. Continua des de qualsevol lloc amb Cloud.",

+ 1 - 2
webview-ui/src/i18n/locales/de/chat.json

@@ -141,8 +141,7 @@
 		"failed": "API-Anfrage fehlgeschlagen",
 		"streaming": "API-Anfrage...",
 		"cancelled": "API-Anfrage abgebrochen",
-		"streamingFailed": "API-Streaming fehlgeschlagen",
-		"viewTokenUsage": "Token-Nutzungsstatistiken anzeigen"
+		"streamingFailed": "API-Streaming fehlgeschlagen"
 	},
 	"checkpoint": {
 		"regular": "Checkpoint",

+ 0 - 11
webview-ui/src/i18n/locales/de/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Roo Code Cloud Konto wechseln",
 	"createTeamAccount": "Team-Konto erstellen",
 	"cloudUrlPillLabel": "Roo Code Cloud URL",
-	"usagePreview": {
-		"costPastDays": "Tägliche Kosten der letzten {{count}} Tage",
-		"seeMoreStats": "Weitere Statistiken in Roo Code Cloud anzeigen",
-		"invalidDataFormat": "Ungültiges Datenformat empfangen",
-		"failedToLoad": "Nutzungsdaten konnten nicht geladen werden",
-		"couldNotLoadChart": "Diagramm konnte nicht geladen werden:",
-		"clickToRetry": "Klicken, um es erneut zu versuchen",
-		"tasks_one": "{{count}} Aufgabe",
-		"tasks_other": "{{count}} Aufgaben",
-		"tokens": "{{count}} Tokens"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Roo etwas Unabhängigkeit geben? Kontrolliere es von überall mit Roo Code Cloud. <learnMoreLink>Mehr erfahren</learnMoreLink>.",
 		"longRunningTask": "Das könnte eine Weile dauern. Mit Cloud von überall weitermachen.",

+ 1 - 2
webview-ui/src/i18n/locales/en/chat.json

@@ -147,8 +147,7 @@
 		"failed": "API Request Failed",
 		"streaming": "API Request...",
 		"cancelled": "API Request Cancelled",
-		"streamingFailed": "API Streaming Failed",
-		"viewTokenUsage": "View token usage stats"
+		"streamingFailed": "API Streaming Failed"
 	},
 	"checkpoint": {
 		"regular": "Checkpoint",

+ 0 - 11
webview-ui/src/i18n/locales/en/cloud.json

@@ -26,17 +26,6 @@
 	"personalAccount": "Personal Account",
 	"switchAccount": "Switch Roo Code Cloud Account",
 	"createTeamAccount": "Create Team Account",
-	"usagePreview": {
-		"costPastDays": "Daily cost past {{count}} days",
-		"seeMoreStats": "See more stats in Roo Code Cloud",
-		"invalidDataFormat": "Invalid data format received",
-		"failedToLoad": "Failed to load usage data",
-		"couldNotLoadChart": "Couldn't load chart:",
-		"clickToRetry": "Click to retry",
-		"tasks_one": "{{count}} task",
-		"tasks_other": "{{count}} tasks",
-		"tokens": "{{count}} tokens"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Giving Roo some independence? Control it from anywhere with Roo Code Cloud. <learnMoreLink>Learn more</learnMoreLink>.",
 		"longRunningTask": "This might take a while. Continue from anywhere with Cloud.",

+ 1 - 2
webview-ui/src/i18n/locales/es/chat.json

@@ -141,8 +141,7 @@
 		"failed": "Solicitud API falló",
 		"streaming": "Solicitud API...",
 		"cancelled": "Solicitud API cancelada",
-		"streamingFailed": "Transmisión API falló",
-		"viewTokenUsage": "Ver estadísticas de uso de tokens"
+		"streamingFailed": "Transmisión API falló"
 	},
 	"checkpoint": {
 		"regular": "Punto de control",

+ 0 - 11
webview-ui/src/i18n/locales/es/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Cambiar Cuenta de Roo Code Cloud",
 	"createTeamAccount": "Crear Cuenta de Equipo",
 	"cloudUrlPillLabel": "URL de Roo Code Cloud",
-	"usagePreview": {
-		"costPastDays": "Costo diario de los últimos {{count}} días",
-		"seeMoreStats": "Ver más estadísticas en Roo Code Cloud",
-		"invalidDataFormat": "Formato de datos recibido no válido",
-		"failedToLoad": "No se pudieron cargar los datos de uso",
-		"couldNotLoadChart": "No se pudo cargar el gráfico:",
-		"clickToRetry": "Haz clic para reintentar",
-		"tasks_one": "{{count}} tarea",
-		"tasks_other": "{{count}} tareas",
-		"tokens": "{{count}} tokens"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "¿Dándole a Roo un poco de independencia? Contrólalo desde cualquier lugar con Roo Code Cloud. <learnMoreLink>Saber más</learnMoreLink>.",
 		"longRunningTask": "Esto podría tardar un poco. Continúa desde cualquier lugar con la Nube.",

+ 1 - 2
webview-ui/src/i18n/locales/fr/chat.json

@@ -141,8 +141,7 @@
 		"failed": "Échec de la requête API",
 		"streaming": "Requête API...",
 		"cancelled": "Requête API annulée",
-		"streamingFailed": "Échec du streaming API",
-		"viewTokenUsage": "Voir les statistiques d'utilisation des tokens"
+		"streamingFailed": "Échec du streaming API"
 	},
 	"checkpoint": {
 		"regular": "Point de contrôle",

+ 0 - 11
webview-ui/src/i18n/locales/fr/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Changer de Compte Roo Code Cloud",
 	"createTeamAccount": "Créer un Compte d'Équipe",
 	"cloudUrlPillLabel": "URL de Roo Code Cloud",
-	"usagePreview": {
-		"costPastDays": "Coût quotidien des {{count}} derniers jours",
-		"seeMoreStats": "Voir plus de statistiques dans Roo Code Cloud",
-		"invalidDataFormat": "Format de données reçu invalide",
-		"failedToLoad": "Échec du chargement des données d'utilisation",
-		"couldNotLoadChart": "Impossible de charger le graphique :",
-		"clickToRetry": "Cliquez pour réessayer",
-		"tasks_one": "{{count}} tâche",
-		"tasks_other": "{{count}} tâches",
-		"tokens": "{{count}} jetons"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Donner à Roo un peu d'indépendance ? Contrôlez-le de n'importe où avec Roo Code Cloud. <learnMoreLink>En savoir plus</learnMoreLink>.",
 		"longRunningTask": "Cela peut prendre un certain temps. Continuez de n'importe où avec le Cloud.",

+ 1 - 2
webview-ui/src/i18n/locales/hi/chat.json

@@ -141,8 +141,7 @@
 		"failed": "API अनुरोध विफल हुआ",
 		"streaming": "API अनुरोध...",
 		"cancelled": "API अनुरोध रद्द किया गया",
-		"streamingFailed": "API स्ट्रीमिंग विफल हुई",
-		"viewTokenUsage": "टोकन उपयोग आँकड़े देखें"
+		"streamingFailed": "API स्ट्रीमिंग विफल हुई"
 	},
 	"checkpoint": {
 		"regular": "चेकपॉइंट",

+ 0 - 11
webview-ui/src/i18n/locales/hi/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Roo Code Cloud खाता बदलें",
 	"createTeamAccount": "टीम खाता बनाएं",
 	"cloudUrlPillLabel": "Roo Code Cloud URL",
-	"usagePreview": {
-		"costPastDays": "पिछले {{count}} दिनों की दैनिक लागत",
-		"seeMoreStats": "रू कोड क्लाउड में और आँकड़े देखें",
-		"invalidDataFormat": "अमान्य डेटा प्रारूप प्राप्त हुआ",
-		"failedToLoad": "उपयोग डेटा लोड करने में विफल",
-		"couldNotLoadChart": "चार्ट लोड नहीं हो सका:",
-		"clickToRetry": "पुनः प्रयास करने के लिए क्लिक करें",
-		"tasks_one": "{{count}} कार्य",
-		"tasks_other": "{{count}} कार्य",
-		"tokens": "{{count}} टोकन"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "रू को थोड़ी स्वतंत्रता दे रहे हैं? रू कोड क्लाउड के साथ इसे कहीं से भी नियंत्रित करें। <learnMoreLink>और जानें</learnMoreLink>।",
 		"longRunningTask": "इसमें थोड़ा समय लग सकता है। क्लाउड के साथ कहीं से भी जारी रखें।",

+ 1 - 2
webview-ui/src/i18n/locales/id/chat.json

@@ -150,8 +150,7 @@
 		"failed": "Permintaan API Gagal",
 		"streaming": "Permintaan API...",
 		"cancelled": "Permintaan API Dibatalkan",
-		"streamingFailed": "Streaming API Gagal",
-		"viewTokenUsage": "Lihat statistik penggunaan token"
+		"streamingFailed": "Streaming API Gagal"
 	},
 	"checkpoint": {
 		"regular": "Checkpoint",

+ 0 - 11
webview-ui/src/i18n/locales/id/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Ganti Akun Roo Code Cloud",
 	"createTeamAccount": "Buat Akun Tim",
 	"cloudUrlPillLabel": "URL Roo Code Cloud",
-	"usagePreview": {
-		"costPastDays": "Biaya harian {{count}} hari terakhir",
-		"seeMoreStats": "Lihat statistik lainnya di Roo Code Cloud",
-		"invalidDataFormat": "Format data yang diterima tidak valid",
-		"failedToLoad": "Gagal memuat data penggunaan",
-		"couldNotLoadChart": "Tidak dapat memuat bagan:",
-		"clickToRetry": "Klik untuk mencoba lagi",
-		"tasks_one": "{{count}} tugas",
-		"tasks_other": "{{count}} tugas",
-		"tokens": "{{count}} token"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Memberi Roo sedikit kebebasan? Kendalikan dari mana saja dengan Roo Code Cloud. <learnMoreLink>Pelajari lebih lanjut</learnMoreLink>.",
 		"longRunningTask": "Ini mungkin akan memakan waktu cukup lama. Lanjutkan dari mana saja dengan Cloud.",

+ 1 - 2
webview-ui/src/i18n/locales/it/chat.json

@@ -144,8 +144,7 @@
 		"failed": "Richiesta API fallita",
 		"streaming": "Richiesta API...",
 		"cancelled": "Richiesta API annullata",
-		"streamingFailed": "Streaming API fallito",
-		"viewTokenUsage": "Visualizza le statistiche di utilizzo dei token"
+		"streamingFailed": "Streaming API fallito"
 	},
 	"checkpoint": {
 		"regular": "Checkpoint",

+ 0 - 11
webview-ui/src/i18n/locales/it/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Cambia Account Roo Code Cloud",
 	"createTeamAccount": "Crea Account del Team",
 	"cloudUrlPillLabel": "URL di Roo Code Cloud",
-	"usagePreview": {
-		"costPastDays": "Costo giornaliero degli ultimi {{count}} giorni",
-		"seeMoreStats": "Vedi altre statistiche in Roo Code Cloud",
-		"invalidDataFormat": "Formato dati ricevuto non valido",
-		"failedToLoad": "Impossibile caricare i dati di utilizzo",
-		"couldNotLoadChart": "Impossibile caricare il grafico:",
-		"clickToRetry": "Clicca per riprovare",
-		"tasks_one": "{{count}} attività",
-		"tasks_other": "{{count}} attività",
-		"tokens": "{{count}} token"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Vuoi dare un po' di indipendenza a Roo? Controllalo da qualsiasi luogo con Roo Code Cloud. <learnMoreLink>Scopri di più</learnMoreLink>.",
 		"longRunningTask": "Potrebbe volerci un po' di tempo. Continua da qualsiasi luogo con il Cloud.",

+ 1 - 2
webview-ui/src/i18n/locales/ja/chat.json

@@ -141,8 +141,7 @@
 		"failed": "APIリクエスト失敗",
 		"streaming": "APIリクエスト...",
 		"cancelled": "APIリクエストキャンセル",
-		"streamingFailed": "APIストリーミング失敗",
-		"viewTokenUsage": "トークン使用状況の統計を表示"
+		"streamingFailed": "APIストリーミング失敗"
 	},
 	"checkpoint": {
 		"regular": "チェックポイント",

+ 0 - 11
webview-ui/src/i18n/locales/ja/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Roo Code Cloud アカウントを切り替え",
 	"createTeamAccount": "チームアカウントを作成",
 	"cloudUrlPillLabel": "Roo Code Cloud URL",
-	"usagePreview": {
-		"costPastDays": "過去{{count}}日間の日次コスト",
-		"seeMoreStats": "Roo Code Cloudでさらに統計を見る",
-		"invalidDataFormat": "無効なデータ形式を受信しました",
-		"failedToLoad": "使用状況データの読み込みに失敗しました",
-		"couldNotLoadChart": "チャートを読み込めませんでした:",
-		"clickToRetry": "クリックして再試行",
-		"tasks_one": "{{count}}タスク",
-		"tasks_other": "{{count}}タスク",
-		"tokens": "{{count}}トークン"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Rooに少し独立性を与えませんか?Roo Code Cloudでどこからでもコントロールできます。<learnMoreLink>詳細</learnMoreLink>。",
 		"longRunningTask": "これには時間がかかるかもしれません。Cloudを使えばどこからでも続けられます。",

+ 1 - 2
webview-ui/src/i18n/locales/ko/chat.json

@@ -141,8 +141,7 @@
 		"failed": "API 요청 실패",
 		"streaming": "API 요청...",
 		"cancelled": "API 요청 취소됨",
-		"streamingFailed": "API 스트리밍 실패",
-		"viewTokenUsage": "토큰 사용 통계 보기"
+		"streamingFailed": "API 스트리밍 실패"
 	},
 	"checkpoint": {
 		"regular": "체크포인트",

+ 0 - 11
webview-ui/src/i18n/locales/ko/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Roo Code Cloud 계정 전환",
 	"createTeamAccount": "팀 계정 만들기",
 	"cloudUrlPillLabel": "Roo Code Cloud URL",
-	"usagePreview": {
-		"costPastDays": "지난 {{count}}일간의 일일 비용",
-		"seeMoreStats": "Roo Code Cloud에서 더 많은 통계 보기",
-		"invalidDataFormat": "잘못된 데이터 형식을 받았습니다",
-		"failedToLoad": "사용 데이터를 로드하지 못했습니다",
-		"couldNotLoadChart": "차트를 로드할 수 없습니다:",
-		"clickToRetry": "클릭하여 다시 시도",
-		"tasks_one": "{{count}}개 작업",
-		"tasks_other": "{{count}}개 작업",
-		"tokens": "{{count}}개 토큰"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Roo에게 약간의 독립성을 부여하시겠습니까? Roo Code Cloud로 어디서든 제어하세요. <learnMoreLink>더 알아보기</learnMoreLink>.",
 		"longRunningTask": "시간이 좀 걸릴 수 있습니다. Cloud로 어디서든 계속하세요.",

+ 1 - 2
webview-ui/src/i18n/locales/nl/chat.json

@@ -136,8 +136,7 @@
 		"failed": "API-verzoek mislukt",
 		"streaming": "API-verzoek...",
 		"cancelled": "API-verzoek geannuleerd",
-		"streamingFailed": "API-streaming mislukt",
-		"viewTokenUsage": "Bekijk tokengebruikstatistieken"
+		"streamingFailed": "API-streaming mislukt"
 	},
 	"checkpoint": {
 		"regular": "Checkpoint",

+ 0 - 11
webview-ui/src/i18n/locales/nl/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Wissel van Roo Code Cloud Account",
 	"createTeamAccount": "Teamaccount aanmaken",
 	"cloudUrlPillLabel": "Roo Code Cloud URL",
-	"usagePreview": {
-		"costPastDays": "Dagelijkse kosten afgelopen {{count}} dagen",
-		"seeMoreStats": "Bekijk meer statistieken in Roo Code Cloud",
-		"invalidDataFormat": "Ongeldig dataformaat ontvangen",
-		"failedToLoad": "Laden van gebruiksgegevens mislukt",
-		"couldNotLoadChart": "Grafiek kon niet geladen worden:",
-		"clickToRetry": "Klik om opnieuw te proberen",
-		"tasks_one": "{{count}} taak",
-		"tasks_other": "{{count}} taken",
-		"tokens": "{{count}} tokens"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Roo wat onafhankelijkheid geven? Bedien het overal met Roo Code Cloud. <learnMoreLink>Meer informatie</learnMoreLink>.",
 		"longRunningTask": "Dit kan even duren. Ga overal verder met de Cloud.",

+ 1 - 2
webview-ui/src/i18n/locales/pl/chat.json

@@ -141,8 +141,7 @@
 		"failed": "Zapytanie API nie powiodło się",
 		"streaming": "Zapytanie API...",
 		"cancelled": "Zapytanie API anulowane",
-		"streamingFailed": "Strumieniowanie API nie powiodło się",
-		"viewTokenUsage": "Wyświetl statystyki użycia tokenów"
+		"streamingFailed": "Strumieniowanie API nie powiodło się"
 	},
 	"checkpoint": {
 		"regular": "Punkt kontrolny",

+ 0 - 11
webview-ui/src/i18n/locales/pl/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Przełącz Konto Roo Code Cloud",
 	"createTeamAccount": "Utwórz Konto Zespołu",
 	"cloudUrlPillLabel": "URL Roo Code Cloud",
-	"usagePreview": {
-		"costPastDays": "Dzienny koszt w ciągu ostatnich {{count}} dni",
-		"seeMoreStats": "Zobacz więcej statystyk w Roo Code Cloud",
-		"invalidDataFormat": "Otrzymano nieprawidłowy format danych",
-		"failedToLoad": "Nie udało się załadować danych o użytkowaniu",
-		"couldNotLoadChart": "Nie można załadować wykresu:",
-		"clickToRetry": "Kliknij, aby ponowić próbę",
-		"tasks_one": "{{count}} zadanie",
-		"tasks_other": "{{count}} zadania",
-		"tokens": "{{count}} tokeny"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Dać Roo trochę niezależności? Kontroluj go z dowolnego miejsca dzięki Roo Code Cloud. <learnMoreLink>Dowiedz się więcej</learnMoreLink>.",
 		"longRunningTask": "To może chwilę potrwać. Kontynuuj z dowolnego miejsca dzięki Chmurze.",

+ 1 - 2
webview-ui/src/i18n/locales/pt-BR/chat.json

@@ -141,8 +141,7 @@
 		"failed": "Requisição API falhou",
 		"streaming": "Requisição API...",
 		"cancelled": "Requisição API cancelada",
-		"streamingFailed": "Streaming API falhou",
-		"viewTokenUsage": "Ver estatísticas de uso de token"
+		"streamingFailed": "Streaming API falhou"
 	},
 	"checkpoint": {
 		"regular": "Ponto de verificação",

+ 0 - 11
webview-ui/src/i18n/locales/pt-BR/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Alternar Conta do Roo Code Cloud",
 	"createTeamAccount": "Criar Conta de Equipe",
 	"cloudUrlPillLabel": "URL do Roo Code Cloud ",
-	"usagePreview": {
-		"costPastDays": "Custo diário dos últimos {{count}} dias",
-		"seeMoreStats": "Veja mais estatísticas no Roo Code Cloud",
-		"invalidDataFormat": "Formato de dados recebido inválido",
-		"failedToLoad": "Falha ao carregar dados de uso",
-		"couldNotLoadChart": "Não foi possível carregar o gráfico:",
-		"clickToRetry": "Clique para tentar novamente",
-		"tasks_one": "{{count}} tarefa",
-		"tasks_other": "{{count}} tarefas",
-		"tokens": "{{count}} tokens"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Dando um pouco de independência ao Roo? Controle-o de qualquer lugar com o Roo Code Cloud. <learnMoreLink>Saiba mais</learnMoreLink>.",
 		"longRunningTask": "Isso pode levar um tempo. Continue de qualquer lugar com a Nuvem.",

+ 1 - 2
webview-ui/src/i18n/locales/ru/chat.json

@@ -136,8 +136,7 @@
 		"failed": "API-запрос не выполнен",
 		"streaming": "API-запрос...",
 		"cancelled": "API-запрос отменен",
-		"streamingFailed": "Ошибка потокового API-запроса",
-		"viewTokenUsage": "Посмотреть статистику использования токенов"
+		"streamingFailed": "Ошибка потокового API-запроса"
 	},
 	"checkpoint": {
 		"regular": "Точка сохранения",

+ 0 - 11
webview-ui/src/i18n/locales/ru/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Переключить аккаунт Roo Code Cloud",
 	"createTeamAccount": "Создать командный аккаунт",
 	"cloudUrlPillLabel": "URL Roo Code Cloud",
-	"usagePreview": {
-		"costPastDays": "Ежедневная стоимость за последние {{count}} дней",
-		"seeMoreStats": "Смотреть больше статистики в Roo Code Cloud",
-		"invalidDataFormat": "Получен неверный формат данных",
-		"failedToLoad": "Не удалось загрузить данные об использовании",
-		"couldNotLoadChart": "Не удалось загрузить диаграмму:",
-		"clickToRetry": "Нажмите, чтобы повторить попытку",
-		"tasks_one": "{{count}} задача",
-		"tasks_other": "{{count}} задачи",
-		"tokens": "{{count}} токенов"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Предоставить Roo немного независимости? Управляйте им из любого места с помощью Roo Code Cloud. <learnMoreLink>Узнать больше</learnMoreLink>.",
 		"longRunningTask": "Это может занять некоторое время. Продолжайте из любого места с помощью Облака.",

+ 1 - 2
webview-ui/src/i18n/locales/tr/chat.json

@@ -141,8 +141,7 @@
 		"failed": "API İsteği Başarısız",
 		"streaming": "API İsteği...",
 		"cancelled": "API İsteği İptal Edildi",
-		"streamingFailed": "API Akışı Başarısız",
-		"viewTokenUsage": "Token kullanım istatistiklerini görüntüle"
+		"streamingFailed": "API Akışı Başarısız"
 	},
 	"checkpoint": {
 		"regular": "Kontrol Noktası",

+ 0 - 11
webview-ui/src/i18n/locales/tr/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Roo Code Cloud Hesabını Değiştir",
 	"createTeamAccount": "Takım Hesabı Oluştur",
 	"cloudUrlPillLabel": "Roo Code Cloud URL'si",
-	"usagePreview": {
-		"costPastDays": "Son {{count}} günün günlük maliyeti",
-		"seeMoreStats": "Roo Code Cloud'da daha fazla istatistik görün",
-		"invalidDataFormat": "Geçersiz veri formatı alındı",
-		"failedToLoad": "Kullanım verileri yüklenemedi",
-		"couldNotLoadChart": "Grafik yüklenemedi:",
-		"clickToRetry": "Yeniden denemek için tıklayın",
-		"tasks_one": "{{count}} görev",
-		"tasks_other": "{{count}} görev",
-		"tokens": "{{count}} token"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Roo'ya biraz bağımsızlık mı veriyorsunuz? Roo Code Cloud ile onu her yerden kontrol edin. <learnMoreLink>Daha fazla bilgi edinin</learnMoreLink>.",
 		"longRunningTask": "Bu biraz zaman alabilir. Bulut ile her yerden devam edin.",

+ 1 - 2
webview-ui/src/i18n/locales/vi/chat.json

@@ -141,8 +141,7 @@
 		"failed": "Yêu cầu API thất bại",
 		"streaming": "Yêu cầu API...",
 		"cancelled": "Yêu cầu API đã hủy",
-		"streamingFailed": "Streaming API thất bại",
-		"viewTokenUsage": "Xem thống kê sử dụng token"
+		"streamingFailed": "Streaming API thất bại"
 	},
 	"checkpoint": {
 		"regular": "Điểm kiểm tra",

+ 0 - 11
webview-ui/src/i18n/locales/vi/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "Chuyển Tài Khoản Roo Code Cloud",
 	"createTeamAccount": "Tạo Tài Khoản Nhóm",
 	"cloudUrlPillLabel": "URL Roo Code Cloud",
-	"usagePreview": {
-		"costPastDays": "Chi phí hàng ngày trong {{count}} ngày qua",
-		"seeMoreStats": "Xem thêm số liệu thống kê trong Roo Code Cloud",
-		"invalidDataFormat": "Định dạng dữ liệu nhận được không hợp lệ",
-		"failedToLoad": "Không thể tải dữ liệu sử dụng",
-		"couldNotLoadChart": "Không thể tải biểu đồ:",
-		"clickToRetry": "Nhấp để thử lại",
-		"tasks_one": "{{count}} nhiệm vụ",
-		"tasks_other": "{{count}} nhiệm vụ",
-		"tokens": "{{count}} token"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "Trao cho Roo một chút độc lập? Kiểm soát nó từ mọi nơi với Roo Code Cloud. <learnMoreLink>Tìm hiểu thêm</learnMoreLink>.",
 		"longRunningTask": "Việc này có thể mất một lúc. Tiếp tục từ mọi nơi với Cloud.",

+ 1 - 2
webview-ui/src/i18n/locales/zh-CN/chat.json

@@ -141,8 +141,7 @@
 		"failed": "API请求失败",
 		"streaming": "API请求...",
 		"cancelled": "API请求已取消",
-		"streamingFailed": "API流式传输失败",
-		"viewTokenUsage": "查看 Token 使用情况统计"
+		"streamingFailed": "API流式传输失败"
 	},
 	"checkpoint": {
 		"regular": "检查点",

+ 0 - 11
webview-ui/src/i18n/locales/zh-CN/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "切换 Roo Code Cloud 账户",
 	"createTeamAccount": "创建团队账户",
 	"cloudUrlPillLabel": "Roo Code Cloud URL",
-	"usagePreview": {
-		"costPastDays": "过去 {{count}} 天的每日费用",
-		"seeMoreStats": "在 Roo Code Cloud 中查看更多统计信息",
-		"invalidDataFormat": "收到的数据格式无效",
-		"failedToLoad": "无法加载使用数据",
-		"couldNotLoadChart": "无法加载图表:",
-		"clickToRetry": "点击重试",
-		"tasks_one": "{{count}} 个任务",
-		"tasks_other": "{{count}} 个任务",
-		"tokens": "{{count}} 令牌"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "给 Roo 一些独立性?使用 Roo Code Cloud 从任何地方控制它。 <learnMoreLink>了解更多</learnMoreLink>。",
 		"longRunningTask": "这可能需要一段时间。使用 Cloud 从任何地方继续。",

+ 1 - 2
webview-ui/src/i18n/locales/zh-TW/chat.json

@@ -147,8 +147,7 @@
 		"failed": "API 請求失敗",
 		"streaming": "正在處理 API 請求...",
 		"cancelled": "API 請求已取消",
-		"streamingFailed": "API 串流處理失敗",
-		"viewTokenUsage": "檢視權杖使用情況統計"
+		"streamingFailed": "API 串流處理失敗"
 	},
 	"checkpoint": {
 		"regular": "檢查點",

+ 0 - 11
webview-ui/src/i18n/locales/zh-TW/cloud.json

@@ -26,17 +26,6 @@
 	"switchAccount": "切換 Roo Code Cloud 帳戶",
 	"createTeamAccount": "創建團隊帳戶",
 	"cloudUrlPillLabel": "Roo Code Cloud URL",
-	"usagePreview": {
-		"costPastDays": "過去 {{count}} 天的每日費用",
-		"seeMoreStats": "在 Roo Code Cloud 中查看更多統計訊息",
-		"invalidDataFormat": "收到的資料格式無效",
-		"failedToLoad": "無法載入使用資料",
-		"couldNotLoadChart": "無法載入圖表:",
-		"clickToRetry": "點擊重試",
-		"tasks_one": "{{count}} 個任務",
-		"tasks_other": "{{count}} 個任務",
-		"tokens": "{{count}} 個 token"
-	},
 	"upsell": {
 		"autoApprovePowerUser": "給 Roo 一點獨立性?使用 Roo Code Cloud 隨時隨地控制它。<learnMoreLink>了解更多</learnMoreLink>。",
 		"longRunningTask": "這可能需要一些時間。使用雲端隨時隨地繼續。",

+ 0 - 13
webview-ui/src/utils/format.ts

@@ -26,15 +26,6 @@ export const formatDate = (timestamp: number) => {
 	})
 }
 
-export const formatDateShort = (timestamp: number) => {
-	const date = new Date(timestamp)
-	const locale = i18next.language || "en"
-	return date.toLocaleDateString(locale, {
-		month: "numeric",
-		day: "numeric",
-	})
-}
-
 export const formatTimeAgo = (timestamp: number) => {
 	const now = Date.now()
 	const diff = now - timestamp
@@ -82,7 +73,3 @@ export const formatTimeAgo = (timestamp: number) => {
 
 	return i18next.t("common:time_ago.just_now")
 }
-
-export const formatCost = (cost: number): string => {
-	return `$${cost.toFixed(2)}`
-}