diff --git a/packages/cloud/src/CloudAPI.ts b/packages/cloud/src/CloudAPI.ts index d1c3f89c2b89..6d7e1dfde148 100644 --- a/packages/cloud/src/CloudAPI.ts +++ b/packages/cloud/src/CloudAPI.ts @@ -1,6 +1,13 @@ import { z } from "zod" -import { type AuthService, type ShareVisibility, type ShareResponse, shareResponseSchema } from "@roo-code/types" +import { + type AuthService, + type ShareVisibility, + type ShareResponse, + shareResponseSchema, + type UsageStats, + usageStatsSchema, +} from "@roo-code/types" import { getRooCodeApiUrl } from "./config.js" import { getUserAgent } from "./utils.js" @@ -53,9 +60,11 @@ 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) { @@ -86,9 +95,15 @@ export class CloudAPI { let responseBody: unknown try { - responseBody = await response.json() - } catch { - responseBody = await response.text() + const bodyText = await response.text() + + try { + responseBody = JSON.parse(bodyText) + } catch { + responseBody = bodyText + } + } catch (_error) { + responseBody = "Failed to read error response" } switch (response.status) { @@ -109,15 +124,12 @@ export class CloudAPI { } async shareTask(taskId: string, visibility: ShareVisibility = "organization"): Promise { - 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 } @@ -134,4 +146,14 @@ export class CloudAPI { .parse(data), }) } + + async getUsagePreview(): Promise { + const response = await this.request("/api/analytics/usage/daily?period=7", { + method: "GET", + parseResponse: (data) => { + return usageStatsSchema.parse(data) + }, + }) + return response + } } diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index af5f9925c353..e7cc9f96aaaf 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -3110,5 +3110,68 @@ 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 + } } } diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 66f389f81c10..09e551b34ab3 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -126,6 +126,7 @@ export interface ExtensionMessage { | "insertTextIntoTextarea" | "dismissedUpsells" | "organizationSwitchResult" + | "usagePreviewData" text?: string payload?: any // Add a generic payload for now, can refine later action?: @@ -205,6 +206,7 @@ export interface ExtensionMessage { queuedMessages?: QueuedMessage[] list?: string[] // For dismissedUpsells organizationId?: string | null // For organizationSwitchResult + data?: any // For usagePreviewData } export type ExtensionState = Pick< diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index d43a2fce0434..97c52ef718e1 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -229,6 +229,7 @@ export interface WebviewMessage { | "editQueuedMessage" | "dismissUpsell" | "getDismissedUpsells" + | "getUsagePreview" text?: string editedMessageContent?: string tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud" diff --git a/webview-ui/src/__tests__/ContextWindowProgress.spec.tsx b/webview-ui/src/__tests__/ContextWindowProgress.spec.tsx index 3c30e15bc6f0..816338adb78d 100644 --- a/webview-ui/src/__tests__/ContextWindowProgress.spec.tsx +++ b/webview-ui/src/__tests__/ContextWindowProgress.spec.tsx @@ -8,6 +8,7 @@ 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 @@ -128,12 +129,7 @@ describe("ContextWindowProgress", () => { expect(windowSize).toBeInTheDocument() expect(windowSize).toHaveTextContent("4000") - // 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 + const progressBarContainer = screen.getByTestId("context-progress-bar-container").parentElement expect(progressBarContainer).toBeInTheDocument() - - // Verify the flex container has the expected structure - expect(progressBarContainer?.querySelector(".flex-1.relative")).toBeInTheDocument() }) }) diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 26bc71074adb..3dc1d3d9e2a2 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -132,7 +132,8 @@ export const ChatRowContent = ({ }: ChatRowContentProps) => { const { t } = useTranslation() - const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode, apiConfiguration } = useExtensionState() + const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode, apiConfiguration, cloudIsAuthenticated } = + useExtensionState() const { info: model } = useSelectedModel(apiConfiguration) const [isEditing, setIsEditing] = useState(false) const [editedContent, setEditedContent] = useState("") @@ -1074,8 +1075,17 @@ export const ChatRowContent = ({ {title}
0 ? 1 : 0 }}> + 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")}> ${Number(cost || 0)?.toFixed(4)}
diff --git a/webview-ui/src/components/chat/ContextWindowProgress.tsx b/webview-ui/src/components/chat/ContextWindowProgress.tsx index 6ddc23882a3f..51903c2c114c 100644 --- a/webview-ui/src/components/chat/ContextWindowProgress.tsx +++ b/webview-ui/src/components/chat/ContextWindowProgress.tsx @@ -60,7 +60,9 @@ export const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens
{/* Main progress bar container */} -
+
{/* Current tokens container */}
- ${totalCost?.toFixed(2)} + {formatCost(totalCost)} + + { + e.stopPropagation() + vscode.postMessage({ + type: "switchTab", + tab: "cloud", + }) + }} + /> + )} diff --git a/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx b/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx index 6cdbeaf0c684..9bc1a7246f26 100644 --- a/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx @@ -88,6 +88,15 @@ vi.mock("@roo/array", () => ({ }, })) +// Mock the format utilities +vi.mock("@/utils/format", async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + formatCost: (cost: number) => `$${cost.toFixed(2)}`, + } +}) + describe("TaskHeader", () => { const defaultProps: TaskHeaderProps = { task: { type: "say", ts: Date.now(), text: "Test task", images: [] }, diff --git a/webview-ui/src/components/cloud/CloudView.tsx b/webview-ui/src/components/cloud/CloudView.tsx index de5fdd003b1b..821f3914108a 100644 --- a/webview-ui/src/components/cloud/CloudView.tsx +++ b/webview-ui/src/components/cloud/CloudView.tsx @@ -9,12 +9,13 @@ 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, Info, Lock, TriangleAlert } from "lucide-react" +import { CircleAlert, 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" @@ -145,6 +146,14 @@ 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) @@ -164,119 +173,128 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone, orga - + {isAuthenticated ? ( - <> - {userInfo && ( -
-
- {userInfo?.picture ? ( - {t("cloud:profilePicture")} - ) : ( -
- {userInfo?.name?.charAt(0) || userInfo?.email?.charAt(0) || "?"} +
+ {/* Content that scrolls */} +
+ {userInfo && ( +
+ {/* Avatar */} +
+ {userInfo?.picture ? ( + {t("cloud:profilePicture")} + ) : ( +
+ {userInfo?.name?.charAt(0) || userInfo?.email?.charAt(0) || "?"} +
+ )} +
+ + {/* Name, email and org switcher */} +
+ {userInfo.name && ( +

+ {userInfo.name} +

+ )} + {userInfo?.email && ( +

+ {userInfo?.email} +

+ )} + + {/* Organization Switcher */} +
+
- )} +
- {userInfo.name && ( -

{userInfo.name}

- )} - {userInfo?.email && ( -

{userInfo?.email}

- )} + )} - {/* Organization Switcher - moved below email */} -
- +
+ + + {t("cloud:taskSync")} + {userInfo?.organizationId && ( + +
+ +
+
+ )} +
+
+
+ {t("cloud:taskSyncDescription")}
-
- )} - - {/* Task Sync Toggle - Always shown when authenticated */} -
-
- - - {t("cloud:taskSync")} - {userInfo?.organizationId && ( - -
- -
-
- )} -
-
-
- {t("cloud:taskSyncDescription")} -
- {/* Remote Control Toggle - Only shown when both extensionBridgeEnabled and featureRoomoteControlEnabled are true */} - {userInfo?.extensionBridgeEnabled && featureRoomoteControlEnabled && ( - <> -
- - - {t("cloud:remoteControl")} - -
-
- {t("cloud:remoteControlDescription")} - {!taskSyncEnabled && ( -
- - {t("cloud:remoteControlRequiresTaskSync")} -
- )} -
- - )} -
+ {/* Remote Control Toggle - Only shown when both extensionBridgeEnabled and featureRoomoteControlEnabled are true */} + {userInfo?.extensionBridgeEnabled && featureRoomoteControlEnabled && ( + <> +
+ + + {t("cloud:remoteControl")} + +
+
+ {t("cloud:remoteControlDescription")} + {!taskSyncEnabled && ( +
+ + {t("cloud:remoteControlRequiresTaskSync")} +
+ )} +
+ + )} +
-
- - {t("cloud:usageMetricsAlwaysReported")} -
+ {/* Usage Stats Chart Section */} +
+ +
-
- - {t("cloud:visitCloudWebsite")} - - - {t("cloud:logOut")} - +
+ + {t("cloud:visitCloudWebsite")} + + + {t("cloud:logOut")} + +
- +
) : ( - <> +
{renderCloudBenefitsContent(t)}
@@ -329,7 +347,7 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone, orga
)}
- +
)} {cloudApiUrl && cloudApiUrl !== PRODUCTION_ROO_CODE_API_URL && (
diff --git a/webview-ui/src/components/cloud/UsagePreview.tsx b/webview-ui/src/components/cloud/UsagePreview.tsx new file mode 100644 index 000000000000..d58160da6b52 --- /dev/null +++ b/webview-ui/src/components/cloud/UsagePreview.tsx @@ -0,0 +1,183 @@ +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(null) + const [data, setData] = useState(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 | 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 ( +
+
+ {/* Loading spinner centered in chart area */} +
+ +
+
+
+ ) + } + + // Error state + if (error || !data) { + return ( +
+
+ {/* Error message in chart area */} +
+ +

{t("cloud:usagePreview.couldNotLoadChart")}

+

{error}

+

{t("cloud:usagePreview.clickToRetry")}

+
+
+
+ ) + } + + return ( +
+
+ {/* Chart with daily usage bars */} +
+ {data && + Array.isArray(data.days) && + data.days.map((day, index) => ( +
+
+ + {formatDateShort(new Date(day.date).getTime())} + +
+ ))} +
+ + {/* Stats text */} +
+ + {t("cloud:usagePreview.costPastDays", { count: data.days.length })} + + + {t("cloud:usagePreview.tasks", { count: data.totals.tasks })} + · + {t("cloud:usagePreview.tokens", { count: formatLargeNumber(data.totals.tokens) })} + · + {formatCost(data.totals.cost)} + +
+
+ + {/* Hover overlay */} +
+
+ {t("cloud:usagePreview.seeMoreStats")} + +
+
+
+ ) +} diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 4d392ee3bf68..74d5176f48a3 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -141,7 +141,8 @@ "failed": "Sol·licitud API ha fallat", "streaming": "Sol·licitud API...", "cancelled": "Sol·licitud API cancel·lada", - "streamingFailed": "Transmissió API ha fallat" + "streamingFailed": "Transmissió API ha fallat", + "viewTokenUsage": "Veure les estadístiques d'ús de fitxes" }, "checkpoint": { "regular": "Punt de control", diff --git a/webview-ui/src/i18n/locales/ca/cloud.json b/webview-ui/src/i18n/locales/ca/cloud.json index e255a4e95dbc..ac64c3d9d937 100644 --- a/webview-ui/src/i18n/locales/ca/cloud.json +++ b/webview-ui/src/i18n/locales/ca/cloud.json @@ -26,6 +26,17 @@ "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. Més informació.", "longRunningTask": "Això pot trigar una estona. Continua des de qualsevol lloc amb Cloud.", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 65934ab5a29c..5ad6302b8367 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -141,7 +141,8 @@ "failed": "API-Anfrage fehlgeschlagen", "streaming": "API-Anfrage...", "cancelled": "API-Anfrage abgebrochen", - "streamingFailed": "API-Streaming fehlgeschlagen" + "streamingFailed": "API-Streaming fehlgeschlagen", + "viewTokenUsage": "Token-Nutzungsstatistiken anzeigen" }, "checkpoint": { "regular": "Checkpoint", diff --git a/webview-ui/src/i18n/locales/de/cloud.json b/webview-ui/src/i18n/locales/de/cloud.json index 2a3a3b1ea4f3..2553660f7443 100644 --- a/webview-ui/src/i18n/locales/de/cloud.json +++ b/webview-ui/src/i18n/locales/de/cloud.json @@ -26,6 +26,17 @@ "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. Mehr erfahren.", "longRunningTask": "Das könnte eine Weile dauern. Mit Cloud von überall weitermachen.", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 9ab37b11497a..3041e7b5a743 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -147,7 +147,8 @@ "failed": "API Request Failed", "streaming": "API Request...", "cancelled": "API Request Cancelled", - "streamingFailed": "API Streaming Failed" + "streamingFailed": "API Streaming Failed", + "viewTokenUsage": "View token usage stats" }, "checkpoint": { "regular": "Checkpoint", diff --git a/webview-ui/src/i18n/locales/en/cloud.json b/webview-ui/src/i18n/locales/en/cloud.json index 05220f83336d..19c842b192e7 100644 --- a/webview-ui/src/i18n/locales/en/cloud.json +++ b/webview-ui/src/i18n/locales/en/cloud.json @@ -26,6 +26,17 @@ "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. Learn more.", "longRunningTask": "This might take a while. Continue from anywhere with Cloud.", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index 30693285db2e..3fec46fa7dc3 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -141,7 +141,8 @@ "failed": "Solicitud API falló", "streaming": "Solicitud API...", "cancelled": "Solicitud API cancelada", - "streamingFailed": "Transmisión API falló" + "streamingFailed": "Transmisión API falló", + "viewTokenUsage": "Ver estadísticas de uso de tokens" }, "checkpoint": { "regular": "Punto de control", diff --git a/webview-ui/src/i18n/locales/es/cloud.json b/webview-ui/src/i18n/locales/es/cloud.json index 9d5830d2393f..76688d19760a 100644 --- a/webview-ui/src/i18n/locales/es/cloud.json +++ b/webview-ui/src/i18n/locales/es/cloud.json @@ -26,6 +26,17 @@ "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. Saber más.", "longRunningTask": "Esto podría tardar un poco. Continúa desde cualquier lugar con la Nube.", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index d5dae24a7913..9ec0427a59eb 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -141,7 +141,8 @@ "failed": "Échec de la requête API", "streaming": "Requête API...", "cancelled": "Requête API annulée", - "streamingFailed": "Échec du streaming API" + "streamingFailed": "Échec du streaming API", + "viewTokenUsage": "Voir les statistiques d'utilisation des tokens" }, "checkpoint": { "regular": "Point de contrôle", diff --git a/webview-ui/src/i18n/locales/fr/cloud.json b/webview-ui/src/i18n/locales/fr/cloud.json index e6e6912be2ac..e24d1f0cb9de 100644 --- a/webview-ui/src/i18n/locales/fr/cloud.json +++ b/webview-ui/src/i18n/locales/fr/cloud.json @@ -26,6 +26,17 @@ "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. En savoir plus.", "longRunningTask": "Cela peut prendre un certain temps. Continuez de n'importe où avec le Cloud.", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 0ec9cd7c7e93..8d3c4581dad4 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -141,7 +141,8 @@ "failed": "API अनुरोध विफल हुआ", "streaming": "API अनुरोध...", "cancelled": "API अनुरोध रद्द किया गया", - "streamingFailed": "API स्ट्रीमिंग विफल हुई" + "streamingFailed": "API स्ट्रीमिंग विफल हुई", + "viewTokenUsage": "टोकन उपयोग आँकड़े देखें" }, "checkpoint": { "regular": "चेकपॉइंट", diff --git a/webview-ui/src/i18n/locales/hi/cloud.json b/webview-ui/src/i18n/locales/hi/cloud.json index dd1b1ebca5a9..a62fd75a8c21 100644 --- a/webview-ui/src/i18n/locales/hi/cloud.json +++ b/webview-ui/src/i18n/locales/hi/cloud.json @@ -26,6 +26,17 @@ "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": "रू को थोड़ी स्वतंत्रता दे रहे हैं? रू कोड क्लाउड के साथ इसे कहीं से भी नियंत्रित करें। और जानें।", "longRunningTask": "इसमें थोड़ा समय लग सकता है। क्लाउड के साथ कहीं से भी जारी रखें।", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index a2c5377691e9..8fb90dfcf2d0 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -150,7 +150,8 @@ "failed": "Permintaan API Gagal", "streaming": "Permintaan API...", "cancelled": "Permintaan API Dibatalkan", - "streamingFailed": "Streaming API Gagal" + "streamingFailed": "Streaming API Gagal", + "viewTokenUsage": "Lihat statistik penggunaan token" }, "checkpoint": { "regular": "Checkpoint", diff --git a/webview-ui/src/i18n/locales/id/cloud.json b/webview-ui/src/i18n/locales/id/cloud.json index 40d4c1e7b3e5..131429ba5d9b 100644 --- a/webview-ui/src/i18n/locales/id/cloud.json +++ b/webview-ui/src/i18n/locales/id/cloud.json @@ -26,6 +26,17 @@ "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. Pelajari lebih lanjut.", "longRunningTask": "Ini mungkin akan memakan waktu cukup lama. Lanjutkan dari mana saja dengan Cloud.", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index a176be1f2fb6..134d157eb4b9 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -144,7 +144,8 @@ "failed": "Richiesta API fallita", "streaming": "Richiesta API...", "cancelled": "Richiesta API annullata", - "streamingFailed": "Streaming API fallito" + "streamingFailed": "Streaming API fallito", + "viewTokenUsage": "Visualizza le statistiche di utilizzo dei token" }, "checkpoint": { "regular": "Checkpoint", diff --git a/webview-ui/src/i18n/locales/it/cloud.json b/webview-ui/src/i18n/locales/it/cloud.json index 944e4dd2d4b2..7e087aa4a5bc 100644 --- a/webview-ui/src/i18n/locales/it/cloud.json +++ b/webview-ui/src/i18n/locales/it/cloud.json @@ -26,6 +26,17 @@ "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. Scopri di più.", "longRunningTask": "Potrebbe volerci un po' di tempo. Continua da qualsiasi luogo con il Cloud.", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 0e940b17ecac..37472739e5d8 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -141,7 +141,8 @@ "failed": "APIリクエスト失敗", "streaming": "APIリクエスト...", "cancelled": "APIリクエストキャンセル", - "streamingFailed": "APIストリーミング失敗" + "streamingFailed": "APIストリーミング失敗", + "viewTokenUsage": "トークン使用状況の統計を表示" }, "checkpoint": { "regular": "チェックポイント", diff --git a/webview-ui/src/i18n/locales/ja/cloud.json b/webview-ui/src/i18n/locales/ja/cloud.json index 6959602b1748..a3b4c3219101 100644 --- a/webview-ui/src/i18n/locales/ja/cloud.json +++ b/webview-ui/src/i18n/locales/ja/cloud.json @@ -26,6 +26,17 @@ "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でどこからでもコントロールできます。詳細。", "longRunningTask": "これには時間がかかるかもしれません。Cloudを使えばどこからでも続けられます。", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 6fa7c5692ac6..43db8803b928 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -141,7 +141,8 @@ "failed": "API 요청 실패", "streaming": "API 요청...", "cancelled": "API 요청 취소됨", - "streamingFailed": "API 스트리밍 실패" + "streamingFailed": "API 스트리밍 실패", + "viewTokenUsage": "토큰 사용 통계 보기" }, "checkpoint": { "regular": "체크포인트", diff --git a/webview-ui/src/i18n/locales/ko/cloud.json b/webview-ui/src/i18n/locales/ko/cloud.json index 962d5e872ab7..4fb99e5e1466 100644 --- a/webview-ui/src/i18n/locales/ko/cloud.json +++ b/webview-ui/src/i18n/locales/ko/cloud.json @@ -26,6 +26,17 @@ "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로 어디서든 제어하세요. 더 알아보기.", "longRunningTask": "시간이 좀 걸릴 수 있습니다. Cloud로 어디서든 계속하세요.", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index 2be312228d27..79f470d5f2bc 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -136,7 +136,8 @@ "failed": "API-verzoek mislukt", "streaming": "API-verzoek...", "cancelled": "API-verzoek geannuleerd", - "streamingFailed": "API-streaming mislukt" + "streamingFailed": "API-streaming mislukt", + "viewTokenUsage": "Bekijk tokengebruikstatistieken" }, "checkpoint": { "regular": "Checkpoint", diff --git a/webview-ui/src/i18n/locales/nl/cloud.json b/webview-ui/src/i18n/locales/nl/cloud.json index dc582e719b7f..d3a0e487fa9b 100644 --- a/webview-ui/src/i18n/locales/nl/cloud.json +++ b/webview-ui/src/i18n/locales/nl/cloud.json @@ -26,6 +26,17 @@ "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. Meer informatie.", "longRunningTask": "Dit kan even duren. Ga overal verder met de Cloud.", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index e60ec330db23..f658c0a35fd0 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -141,7 +141,8 @@ "failed": "Zapytanie API nie powiodło się", "streaming": "Zapytanie API...", "cancelled": "Zapytanie API anulowane", - "streamingFailed": "Strumieniowanie API nie powiodło się" + "streamingFailed": "Strumieniowanie API nie powiodło się", + "viewTokenUsage": "Wyświetl statystyki użycia tokenów" }, "checkpoint": { "regular": "Punkt kontrolny", diff --git a/webview-ui/src/i18n/locales/pl/cloud.json b/webview-ui/src/i18n/locales/pl/cloud.json index 790d2cdf741e..f0aa96655339 100644 --- a/webview-ui/src/i18n/locales/pl/cloud.json +++ b/webview-ui/src/i18n/locales/pl/cloud.json @@ -26,6 +26,17 @@ "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. Dowiedz się więcej.", "longRunningTask": "To może chwilę potrwać. Kontynuuj z dowolnego miejsca dzięki Chmurze.", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index 3408f3a1aa91..6d31bd45a198 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -141,7 +141,8 @@ "failed": "Requisição API falhou", "streaming": "Requisição API...", "cancelled": "Requisição API cancelada", - "streamingFailed": "Streaming API falhou" + "streamingFailed": "Streaming API falhou", + "viewTokenUsage": "Ver estatísticas de uso de token" }, "checkpoint": { "regular": "Ponto de verificação", diff --git a/webview-ui/src/i18n/locales/pt-BR/cloud.json b/webview-ui/src/i18n/locales/pt-BR/cloud.json index 1d979d46d743..7b9bbff6b360 100644 --- a/webview-ui/src/i18n/locales/pt-BR/cloud.json +++ b/webview-ui/src/i18n/locales/pt-BR/cloud.json @@ -26,6 +26,17 @@ "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. Saiba mais.", "longRunningTask": "Isso pode levar um tempo. Continue de qualquer lugar com a Nuvem.", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 5018f817aff5..c596fde8dea2 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -136,7 +136,8 @@ "failed": "API-запрос не выполнен", "streaming": "API-запрос...", "cancelled": "API-запрос отменен", - "streamingFailed": "Ошибка потокового API-запроса" + "streamingFailed": "Ошибка потокового API-запроса", + "viewTokenUsage": "Посмотреть статистику использования токенов" }, "checkpoint": { "regular": "Точка сохранения", diff --git a/webview-ui/src/i18n/locales/ru/cloud.json b/webview-ui/src/i18n/locales/ru/cloud.json index 99313da1fcf9..1a49e8fabd3c 100644 --- a/webview-ui/src/i18n/locales/ru/cloud.json +++ b/webview-ui/src/i18n/locales/ru/cloud.json @@ -26,6 +26,17 @@ "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. Узнать больше.", "longRunningTask": "Это может занять некоторое время. Продолжайте из любого места с помощью Облака.", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 2290a85f6dfe..d213b2b6bf5f 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -141,7 +141,8 @@ "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" + "streamingFailed": "API Akışı Başarısız", + "viewTokenUsage": "Token kullanım istatistiklerini görüntüle" }, "checkpoint": { "regular": "Kontrol Noktası", diff --git a/webview-ui/src/i18n/locales/tr/cloud.json b/webview-ui/src/i18n/locales/tr/cloud.json index daf90da84d3d..2de37002e020 100644 --- a/webview-ui/src/i18n/locales/tr/cloud.json +++ b/webview-ui/src/i18n/locales/tr/cloud.json @@ -26,6 +26,17 @@ "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. Daha fazla bilgi edinin.", "longRunningTask": "Bu biraz zaman alabilir. Bulut ile her yerden devam edin.", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index d9362ea39dde..4225aeb51dbb 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -141,7 +141,8 @@ "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" + "streamingFailed": "Streaming API thất bại", + "viewTokenUsage": "Xem thống kê sử dụng token" }, "checkpoint": { "regular": "Điểm kiểm tra", diff --git a/webview-ui/src/i18n/locales/vi/cloud.json b/webview-ui/src/i18n/locales/vi/cloud.json index a3ad623da98e..c50766ef09f5 100644 --- a/webview-ui/src/i18n/locales/vi/cloud.json +++ b/webview-ui/src/i18n/locales/vi/cloud.json @@ -26,6 +26,17 @@ "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. Tìm hiểu thêm.", "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.", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 850f79e63038..8c7252844b8a 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -141,7 +141,8 @@ "failed": "API请求失败", "streaming": "API请求...", "cancelled": "API请求已取消", - "streamingFailed": "API流式传输失败" + "streamingFailed": "API流式传输失败", + "viewTokenUsage": "查看 Token 使用情况统计" }, "checkpoint": { "regular": "检查点", diff --git a/webview-ui/src/i18n/locales/zh-CN/cloud.json b/webview-ui/src/i18n/locales/zh-CN/cloud.json index 1fce239f63d5..59c060b41393 100644 --- a/webview-ui/src/i18n/locales/zh-CN/cloud.json +++ b/webview-ui/src/i18n/locales/zh-CN/cloud.json @@ -26,6 +26,17 @@ "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 从任何地方控制它。 了解更多。", "longRunningTask": "这可能需要一段时间。使用 Cloud 从任何地方继续。", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 24a67b13a9a5..f013ac53757e 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -147,7 +147,8 @@ "failed": "API 請求失敗", "streaming": "正在處理 API 請求...", "cancelled": "API 請求已取消", - "streamingFailed": "API 串流處理失敗" + "streamingFailed": "API 串流處理失敗", + "viewTokenUsage": "檢視權杖使用情況統計" }, "checkpoint": { "regular": "檢查點", diff --git a/webview-ui/src/i18n/locales/zh-TW/cloud.json b/webview-ui/src/i18n/locales/zh-TW/cloud.json index 54cecf1af2ae..77a909a3b9f0 100644 --- a/webview-ui/src/i18n/locales/zh-TW/cloud.json +++ b/webview-ui/src/i18n/locales/zh-TW/cloud.json @@ -26,6 +26,17 @@ "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 隨時隨地控制它。了解更多。", "longRunningTask": "這可能需要一些時間。使用雲端隨時隨地繼續。", diff --git a/webview-ui/src/utils/format.ts b/webview-ui/src/utils/format.ts index 29c7a2c96632..9fa2b6044e17 100644 --- a/webview-ui/src/utils/format.ts +++ b/webview-ui/src/utils/format.ts @@ -26,6 +26,15 @@ 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 @@ -73,3 +82,7 @@ export const formatTimeAgo = (timestamp: number) => { return i18next.t("common:time_ago.just_now") } + +export const formatCost = (cost: number): string => { + return `$${cost.toFixed(2)}` +}