From 53f1bdc70c32819cee2580ec22bd20014399732b Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Fri, 18 Apr 2025 17:12:42 -0600 Subject: [PATCH 1/5] isotrUpdate welcome screen UI components and fix unused variable --- .../src/components/chat/Announcement.tsx | 110 +++++++------- webview-ui/src/components/chat/ChatView.tsx | 134 +++++++----------- .../src/components/chat/ContextMenu.tsx | 4 +- .../src/components/history/HistoryPreview.tsx | 48 +++---- webview-ui/src/components/welcome/RooHero.tsx | 9 +- webview-ui/src/components/welcome/RooTips.tsx | 93 ++++++++++++ .../welcome/__tests__/RooTips.test.tsx | 74 ++++++++++ webview-ui/src/i18n/locales/en/chat.json | 19 ++- 8 files changed, 317 insertions(+), 174 deletions(-) create mode 100644 webview-ui/src/components/welcome/RooTips.tsx create mode 100644 webview-ui/src/components/welcome/__tests__/RooTips.test.tsx diff --git a/webview-ui/src/components/chat/Announcement.tsx b/webview-ui/src/components/chat/Announcement.tsx index ec23707dd59..2dec582f7c9 100644 --- a/webview-ui/src/components/chat/Announcement.tsx +++ b/webview-ui/src/components/chat/Announcement.tsx @@ -42,66 +42,68 @@ const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => { ) return ( -
- - - -

{t("chat:announcement.title")}

+
+
+ + + +

{t("chat:announcement.title")}

-

{t("chat:announcement.description")}

+

{t("chat:announcement.description")}

-

{t("chat:announcement.whatsNew")}

-
    -
  • - •{" "} - , - }} - /> -
  • -
  • - •{" "} - , - }} - /> -
  • -
  • - •{" "} +

    {t("chat:announcement.whatsNew")}

    +
      +
    • + •{" "} + , + }} + /> +
    • +
    • + •{" "} + , + }} + /> +
    • +
    • + •{" "} + , + }} + /> +
    • +
    + +

    , + discordLink: discordLink, + redditLink: redditLink, }} /> -

  • -
- -

- -

+

+
) } diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index c287a99cbb9..12f213a2649 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -3,7 +3,6 @@ import debounce from "debounce" import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react" import { useDeepCompareEffect, useEvent, useMount } from "react-use" import { Virtuoso, type VirtuosoHandle } from "react-virtuoso" -import styled from "styled-components" import { ClineAsk, ClineMessage, @@ -19,7 +18,8 @@ import { getApiMetrics } from "@roo/shared/getApiMetrics" import { useExtensionState } from "@src/context/ExtensionStateContext" import { vscode } from "@src/utils/vscode" import HistoryPreview from "../history/HistoryPreview" -import RooHero from "../welcome/RooHero" +import RooHero from "@src/components/welcome/RooHero" +import RooTips from "@src/components/welcome/RooTips" import { normalizeApiConfiguration } from "../settings/ApiOptions" import Announcement from "./Announcement" import BrowserSessionRow from "./BrowserSessionRow" @@ -35,6 +35,7 @@ import TelemetryBanner from "../common/TelemetryBanner" import { useAppTranslation } from "@/i18n/TranslationContext" import removeMd from "remove-markdown" import { Trans } from "react-i18next" +import { useTaskSearch } from "@/components/history/useTaskSearch" interface ChatViewProps { isHidden: boolean showAnnouncement: boolean @@ -81,6 +82,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined const task = useMemo(() => messages.at(0), [messages]) // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see Cline.abort) const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages]) @@ -1194,17 +1197,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction +
{task ? ( <> ) : ( -
+
{telemetrySetting === "unset" && } {showAnnouncement && } + {/* Always show the hero. */} + {/* If the user has no task history, we can show the onboarding message */} + {!taskHistory.length && ( +

+ + the docs + + ), + }} + /> +

+ )} + + {/* Show the task history if there are any for this workspace. */} {taskHistory.length > 0 && } + {/* Finally, if there less than 3 tasks, we can show the tips */} + {tasks.length < 3 && 0)} />}
)} @@ -1267,28 +1275,20 @@ const ChatViewComponent: React.ForwardRefRenderFunction +
+ +
)} {task && ( <> -
+
, // Add empty padding at the bottom + Footer: () =>
, // Add empty padding at the bottom }} // increasing top by 3_000 to prevent jumping around when user collapses a row increaseViewportBy={{ top: 3_000, bottom: Number.MAX_SAFE_INTEGER }} // hack to make sure the last message is always rendered to get truly perfect scroll to bottom animation when new messages are added (Number.MAX_SAFE_INTEGER is safe for arithmetic operations, which is all virtuoso uses this value for in src/sizeRangeSystem.ts) @@ -1307,40 +1307,33 @@ const ChatViewComponent: React.ForwardRefRenderFunction {showScrollToBottom ? ( -
- +
{ scrollToBottomSmooth() disableAutoScrollRef.current = false }} title={t("chat:scrollToBottom")}> - - + +
) : (
+ className={`flex ${ + primaryButtonText || secondaryButtonText || isStreaming ? "px-[15px] pt-[10px]" : "p-0" + } ${ + primaryButtonText || secondaryButtonText || isStreaming + ? enableButtons || (isStreaming && !didClickCancel) + ? "opacity-100" + : "opacity-50" + : "opacity-0" + }`}> {primaryButtonText && !isStreaming && ( = ({ diff --git a/webview-ui/src/components/history/HistoryPreview.tsx b/webview-ui/src/components/history/HistoryPreview.tsx index 3d3a5f0a13a..82bfcb909c3 100644 --- a/webview-ui/src/components/history/HistoryPreview.tsx +++ b/webview-ui/src/components/history/HistoryPreview.tsx @@ -9,6 +9,7 @@ import { CopyButton } from "./CopyButton" import { useTaskSearch } from "./useTaskSearch" import { Trans } from "react-i18next" +import { Coins } from "lucide-react" type HistoryPreviewProps = { showHistoryView: () => void @@ -20,20 +21,21 @@ const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => { return ( <>
- {!!tasks.length && ( -
+ {tasks.length !== 0 && ( +
{t("history:recentTasks")}
)} + {tasks.length === 0 && ( <> -

+

{ />

- )} + {tasks.slice(0, 3).map((item) => (
vscode.postMessage({ type: "showTaskWithId", text: item.id })}>
@@ -67,39 +71,23 @@ const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => {
{item.task}
-
- - {t("history:tokens", { - in: formatLargeNumber(item.tokensIn || 0), - out: formatLargeNumber(item.tokensOut || 0), - })} - - {!!item.cacheWrites && ( - <> - {" • "} - - {t("history:cache", { - writes: formatLargeNumber(item.cacheWrites || 0), - reads: formatLargeNumber(item.cacheReads || 0), - })} - - - )} +
+ ↑ {formatLargeNumber(item.tokensIn || 0)} + ↓ {formatLargeNumber(item.tokensOut || 0)} {!!item.totalCost && ( - <> - {" • "} - {t("history:apiCost", { cost: item.totalCost?.toFixed(4) })} - + + {"$" + item.totalCost?.toFixed(2)} + )}
{showAllWorkspaces && item.workspace && ( diff --git a/webview-ui/src/components/welcome/RooHero.tsx b/webview-ui/src/components/welcome/RooHero.tsx index f4be0b6c070..bc99dbd004d 100644 --- a/webview-ui/src/components/welcome/RooHero.tsx +++ b/webview-ui/src/components/welcome/RooHero.tsx @@ -1,7 +1,7 @@ import { useState } from "react" -import { useAppTranslation } from "@src/i18n/TranslationContext" +import { useAppTranslation } from "../../i18n/TranslationContext" -const WelcomeView = () => { +const RooHero = () => { const { t } = useAppTranslation() const [imagesBaseUri] = useState(() => { @@ -10,7 +10,7 @@ const WelcomeView = () => { }) return ( -
+
{ className="mx-auto"> Roo logo
+

{t("chat:greeting")}

) } -export default WelcomeView +export default RooHero diff --git a/webview-ui/src/components/welcome/RooTips.tsx b/webview-ui/src/components/welcome/RooTips.tsx new file mode 100644 index 00000000000..597449bb4a0 --- /dev/null +++ b/webview-ui/src/components/welcome/RooTips.tsx @@ -0,0 +1,93 @@ +import { VSCodeLink } from "@vscode/webview-ui-toolkit/react" +import { useTranslation } from "react-i18next" +import { useState, useEffect } from "react" +import clsx from "clsx" + +const tips = [ + { + icon: "codicon-list-tree", + href: "https://docs.roocode.com/features/boomerang-tasks", + titleKey: "rooTips.boomerangTasks.title", + descriptionKey: "rooTips.boomerangTasks.description", + }, + { + icon: "codicon-pinned", + href: "https://docs.roocode.com/basic-usage/using-modes", + titleKey: "rooTips.stickyModels.title", + descriptionKey: "rooTips.stickyModels.description", + }, + { + icon: "codicon-tools", + href: "https://docs.roocode.com/basic-usage/how-tools-work", + titleKey: "rooTips.tools.title", + descriptionKey: "rooTips.tools.description", + }, +] + +interface RooTipsProps { + cycle?: boolean +} + +const RooTips = ({ cycle = true }: RooTipsProps) => { + const { t } = useTranslation("chat") + const [currentTipIndex, setCurrentTipIndex] = useState(Math.floor(Math.random() * tips.length)) + const [isFading, setIsFading] = useState(false) + + useEffect(() => { + if (!cycle) return + + const intervalId = setInterval(() => { + setIsFading(true) // Start fade out + setTimeout(() => { + setCurrentTipIndex((prevIndex) => (prevIndex + 1) % tips.length) + setIsFading(false) // Start fade in + }, 1000) // Fade duration + }, 11000) // 10s display + 1s fade + + return () => clearInterval(intervalId) // Cleanup on unmount + }, [cycle]) + + const currentTip = tips[currentTipIndex] + const topTwoTips = tips.slice(0, 2) + + return ( +
+ {/* If we need real estate, we show a compressed version of the tips. Otherwise, we expand it. */} + {cycle ? ( + <> +
Did you know about...
+
+ {" "} + {/* Corrected backtick to parenthesis */} + + + {t(currentTip.titleKey)}:{" "} + {t(currentTip.descriptionKey)} + +
+ + ) : ( + topTwoTips.map((tip) => ( +
+ + + {t(tip.titleKey)}: {t(tip.descriptionKey)} + +
+ )) + )} +
+ ) +} + +export default RooTips diff --git a/webview-ui/src/components/welcome/__tests__/RooTips.test.tsx b/webview-ui/src/components/welcome/__tests__/RooTips.test.tsx new file mode 100644 index 00000000000..fdd49db4eb1 --- /dev/null +++ b/webview-ui/src/components/welcome/__tests__/RooTips.test.tsx @@ -0,0 +1,74 @@ +import { render, screen, act } from "@testing-library/react" +import RooTips from "../RooTips" +import React from "react" // Import React for JSX types + +// Mock the translation hook +jest.mock("react-i18next", () => ({ + useTranslation: () => ({ + t: (key: string) => key, // Simple mock that returns the key + }), + Trans: ({ children }: { children: React.ReactNode }) => children, +})) + +// Mock VSCodeLink +jest.mock("@vscode/webview-ui-toolkit/react", () => ({ + VSCodeLink: ({ href, children }: { href: string; children: React.ReactNode }) => {children}, +})) + +describe("RooTips Component", () => { + beforeEach(() => { + jest.useFakeTimers() + }) + + afterEach(() => { + jest.runOnlyPendingTimers() + jest.useRealTimers() + }) + + test("renders and cycles through tips by default (cycle=true)", () => { + render() + + // Initial render (random tip) - check if one tip is rendered + // We check for the link text pattern as the description is included + expect(screen.getByRole("link", { name: /rooTips\..*\.title/i })).toBeInTheDocument() + expect(screen.getAllByRole("link")).toHaveLength(1) + + // Fast-forward time to trigger the interval + fade timeout + act(() => { + jest.advanceTimersByTime(11000 + 1000) // interval + fade duration + }) + + // After interval, a different tip should be potentially rendered (still one tip) + // Note: Due to random start, we can't guarantee a *different* tip if there are only 2, + // but the core logic is that it attempts to cycle. We re-check the structure. + expect(screen.getByRole("link", { name: /rooTips\..*\.title/i })).toBeInTheDocument() + expect(screen.getAllByRole("link")).toHaveLength(1) + }) + + test("renders only the top two tips when cycle is false", () => { + render() + + // Check if the first two tips are rendered + expect(screen.getByRole("link", { name: "rooTips.boomerangTasks.title" })).toBeInTheDocument() + expect(screen.getByText("rooTips.boomerangTasks.description")).toBeInTheDocument() + expect(screen.getByRole("link", { name: "rooTips.stickyModels.title" })).toBeInTheDocument() + expect(screen.getByText("rooTips.stickyModels.description")).toBeInTheDocument() + + // Ensure only two tips are present + expect(screen.getAllByRole("link")).toHaveLength(2) + + // Check that the third tip is not rendered + expect(screen.queryByRole("link", { name: "rooTips.tools.title" })).not.toBeInTheDocument() + + // Fast-forward time - nothing should change + act(() => { + jest.advanceTimersByTime(12000) + }) + + // Verify the state remains the same (still top two tips) + expect(screen.getByRole("link", { name: "rooTips.boomerangTasks.title" })).toBeInTheDocument() + expect(screen.getByRole("link", { name: "rooTips.stickyModels.title" })).toBeInTheDocument() + expect(screen.getAllByRole("link")).toHaveLength(2) + expect(screen.queryByRole("link", { name: "rooTips.tools.title" })).not.toBeInTheDocument() + }) +}) diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index f1609b19a63..b02cb12a324 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -65,7 +65,8 @@ "tooltip": "Cancel the current operation" }, "scrollToBottom": "Scroll to bottom of chat", - "onboarding": "Your task list in this workspace is empty. Start by typing in a task below. Not sure how to begin? Read more about what Roo can do for you in the docs.", + "about": "Generate, refactor, and debug code with AI assistance.
Check out our documentation to learn more.", + "onboarding": "Your task list in this workspace is empty.", "selectMode": "Select mode for interaction", "selectApiConfig": "Select API configuration", "enhancePrompt": "Enhance prompt with additional context", @@ -217,5 +218,19 @@ "close": "Close browser" } }, - "systemPromptWarning": "WARNING: Custom system prompt override active. This can severely break functionality and cause unpredictable behavior." + "systemPromptWarning": "WARNING: Custom system prompt override active. This can severely break functionality and cause unpredictable behavior.", + "rooTips": { + "boomerangTasks": { + "title": "Boomerang Tasks", + "description": "Orchestrate complex workflows with subtasks" + }, + "stickyModels": { + "title": "Sticky Models", + "description": "Each mode remembers your last used model" + }, + "tools": { + "title": "Tools", + "description": "Allow the AI to solve problems by browsing the web, running commands, and more." + } + } } From 660d142c5b1a3489ed68cda6cd01f3b4be853d01 Mon Sep 17 00:00:00 2001 From: Sacha Sayan Date: Fri, 25 Apr 2025 10:30:26 -0400 Subject: [PATCH 2/5] Save collapsibility. --- src/core/webview/ClineProvider.ts | 3 + src/core/webview/webviewMessageHandler.ts | 4 + src/shared/ExtensionMessage.ts | 2 + .../src/components/history/HistoryPreview.tsx | 107 +++++++++++------- .../src/context/ExtensionStateContext.tsx | 5 + 5 files changed, 80 insertions(+), 41 deletions(-) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 16984a4a49e..67c709d7f53 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1243,6 +1243,7 @@ export class ClineProvider extends EventEmitter implements showRooIgnoredFiles, language, maxReadFileLine, + historyPreviewCollapsed, // Destructure the new state value } = await this.getState() const telemetryKey = process.env.POSTHOG_API_KEY @@ -1327,6 +1328,7 @@ export class ClineProvider extends EventEmitter implements maxReadFileLine: maxReadFileLine ?? 500, settingsImportedAt: this.settingsImportedAt, hasSystemPromptOverride, + historyPreviewCollapsed: historyPreviewCollapsed ?? false, // Add to the returned state object } } @@ -1414,6 +1416,7 @@ export class ClineProvider extends EventEmitter implements telemetrySetting: stateValues.telemetrySetting || "unset", showRooIgnoredFiles: stateValues.showRooIgnoredFiles ?? true, maxReadFileLine: stateValues.maxReadFileLine ?? 500, + historyPreviewCollapsed: stateValues.historyPreviewCollapsed ?? false, // Add to the internal getState as well } } diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 639c3b477fe..2d2b1315c65 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -943,6 +943,10 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We await updateGlobalState("maxReadFileLine", message.value) await provider.postStateToWebview() break + case "setHistoryPreviewCollapsed": // Add the new case handler + await updateGlobalState("historyPreviewCollapsed", message.bool ?? false) + // No need to call postStateToWebview here as the UI already updated optimistically + break case "toggleApiConfigPin": if (message.text) { const currentPinned = getGlobalState("pinnedApiConfigs") ?? {} diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 25a3133e30b..ba43b46a0a1 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -69,6 +69,7 @@ export interface ExtensionMessage { | "fileSearchResults" | "toggleApiConfigPin" | "acceptInput" + | "setHistoryPreviewCollapsed" // Add the new message type text?: string action?: | "chatButtonClicked" @@ -206,6 +207,7 @@ export type ExtensionState = Pick< renderContext: "sidebar" | "editor" settingsImportedAt?: number + historyPreviewCollapsed?: boolean // Add the new state property } export type { ClineMessage, ClineAsk, ClineSay } diff --git a/webview-ui/src/components/history/HistoryPreview.tsx b/webview-ui/src/components/history/HistoryPreview.tsx index 82bfcb909c3..21a1f0bbd72 100644 --- a/webview-ui/src/components/history/HistoryPreview.tsx +++ b/webview-ui/src/components/history/HistoryPreview.tsx @@ -1,10 +1,11 @@ -import { memo } from "react" +import { memo, useState, useCallback } from "react" import { vscode } from "@/utils/vscode" import { formatLargeNumber, formatDate } from "@/utils/format" import { Button } from "@/components/ui" import { useAppTranslation } from "@src/i18n/TranslationContext" +import { useExtensionState } from "@src/context/ExtensionStateContext" import { CopyButton } from "./CopyButton" import { useTaskSearch } from "./useTaskSearch" @@ -16,17 +17,30 @@ type HistoryPreviewProps = { } const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => { const { tasks, showAllWorkspaces } = useTaskSearch() + const { historyPreviewCollapsed } = useExtensionState() // Will add this state later const { t } = useAppTranslation() + // Initialize expanded state based on the persisted setting (default to expanded if undefined) + const [isExpanded, setIsExpanded] = useState( + historyPreviewCollapsed === undefined ? true : !historyPreviewCollapsed, + ) + + const toggleExpanded = useCallback(() => { + const newState = !isExpanded + setIsExpanded(newState) + // Send message to extension to persist the new collapsed state + vscode.postMessage({ type: "setHistoryPreviewCollapsed", bool: !newState }) + }, [isExpanded]) return ( <>
{tasks.length !== 0 && (
-
- +
+ {t("history:recentTasks")}
+ {/* Keep the history button, but maybe it should just show the full view? Or remove it if header is clicked? Let's keep it for now. */} @@ -58,47 +72,58 @@ const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => { )} - {tasks.slice(0, 3).map((item) => ( -
vscode.postMessage({ type: "showTaskWithId", text: item.id })}> -
-
- - {formatDate(item.ts)} - - -
+ {tasks.length !== 0 && isExpanded && ( + <> + {tasks.slice(0, 3).map((item) => (
- {item.task} -
-
- ↑ {formatLargeNumber(item.tokensIn || 0)} - ↓ {formatLargeNumber(item.tokensOut || 0)} - {!!item.totalCost && ( - - {"$" + item.totalCost?.toFixed(2)} - - )} -
- {showAllWorkspaces && item.workspace && ( -
- - {item.workspace} + key={item.id} + className="bg-vscode-editor-background rounded relative overflow-hidden cursor-pointer border border-vscode-toolbar-hoverBackground/30 hover:border-vscode-toolbar-hoverBackground/60" + onClick={() => vscode.postMessage({ type: "showTaskWithId", text: item.id })}> +
+
+ + {formatDate(item.ts)} + + +
+
+ {item.task} +
+
+ ↑ {formatLargeNumber(item.tokensIn || 0)} + ↓ {formatLargeNumber(item.tokensOut || 0)} + {!!item.totalCost && ( + + {" "} + {"$" + item.totalCost?.toFixed(2)} + + )} +
+ {showAllWorkspaces && item.workspace && ( +
+ + {item.workspace} +
+ )}
- )} +
+ ))} + {/* Add a "View All" link below the preview list when expanded */} +
showHistoryView()}> + {t("history:viewAll")} ({tasks.length})
-
- ))} + + )}
) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index 90629edfb13..1c3b81848f2 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -13,6 +13,7 @@ import { experimentDefault, ExperimentId } from "@roo/shared/experiments" import { TelemetrySetting } from "@roo/shared/TelemetrySetting" export interface ExtensionStateContextType extends ExtensionState { + historyPreviewCollapsed?: boolean // Add the new state property didHydrateState: boolean showWelcome: boolean theme: any @@ -87,6 +88,7 @@ export interface ExtensionStateContextType extends ExtensionState { pinnedApiConfigs?: Record setPinnedApiConfigs: (value: Record) => void togglePinnedApiConfig: (configName: string) => void + setHistoryPreviewCollapsed: (value: boolean) => void // Add the setter function type } export const ExtensionStateContext = createContext(undefined) @@ -163,6 +165,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode terminalZshOhMy: false, // Default Oh My Zsh integration setting terminalZshP10k: false, // Default Powerlevel10k integration setting terminalZdotdir: false, // Default ZDOTDIR handling setting + historyPreviewCollapsed: false, // Initialize the new state (default to expanded) }) const [didHydrateState, setDidHydrateState] = useState(false) @@ -331,6 +334,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode return { ...prevState, pinnedApiConfigs: newPinned } }), + setHistoryPreviewCollapsed: (value) => + setState((prevState) => ({ ...prevState, historyPreviewCollapsed: value })), // Implement the setter } return {children} From 080f108fdadbdcbe623081523fa9d8070c5ca2cf Mon Sep 17 00:00:00 2001 From: Sacha Sayan Date: Fri, 25 Apr 2025 11:04:02 -0400 Subject: [PATCH 3/5] Add persistence, locales. --- src/core/config/ContextProxy.ts | 14 ++++++++++++++ src/core/webview/ClineProvider.ts | 2 ++ src/exports/roo-code.d.ts | 1 + src/exports/types.ts | 1 + src/schemas/index.ts | 2 ++ src/shared/WebviewMessage.ts | 1 + webview-ui/src/i18n/locales/ca/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/de/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/en/chat.json | 14 ++++++++++++++ webview-ui/src/i18n/locales/es/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/fr/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/hi/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/it/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/ja/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/ko/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/pl/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/pt-BR/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/tr/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/vi/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/zh-CN/chat.json | 16 +++++++++++++++- webview-ui/src/i18n/locales/zh-TW/chat.json | 16 +++++++++++++++- 21 files changed, 245 insertions(+), 14 deletions(-) diff --git a/src/core/config/ContextProxy.ts b/src/core/config/ContextProxy.ts index aa40477ad81..6148dbf91d5 100644 --- a/src/core/config/ContextProxy.ts +++ b/src/core/config/ContextProxy.ts @@ -53,12 +53,26 @@ export class ContextProxy { public async initialize() { for (const key of GLOBAL_STATE_KEYS) { try { + // Revert to original assignment this.stateCache[key] = this.originalContext.globalState.get(key) } catch (error) { logger.error(`Error loading global ${key}: ${error instanceof Error ? error.message : String(error)}`) } } + // Explicitly load historyPreviewCollapsed after the main loop + try { + const historyCollapsedValue = this.originalContext.globalState.get("historyPreviewCollapsed") + if (typeof historyCollapsedValue === "boolean") { + this.stateCache.historyPreviewCollapsed = historyCollapsedValue + } + // No logging needed here anymore + } catch (error) { + logger.error( + `Error loading global historyPreviewCollapsed: ${error instanceof Error ? error.message : String(error)}`, + ) + } + const promises = SECRET_STATE_KEYS.map(async (key) => { try { this.secretCache[key] = await this.originalContext.secrets.get(key) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 67c709d7f53..370d1da3a64 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1246,6 +1246,8 @@ export class ClineProvider extends EventEmitter implements historyPreviewCollapsed, // Destructure the new state value } = await this.getState() + this.log(`[Debug] getState historyPreviewCollapsed: ${historyPreviewCollapsed}`) // Add logging here + const telemetryKey = process.env.POSTHOG_API_KEY const machineId = vscode.env.machineId const allowedCommands = vscode.workspace.getConfiguration("roo-cline").get("allowedCommands") || [] diff --git a/src/exports/roo-code.d.ts b/src/exports/roo-code.d.ts index 5883cb86417..179fb03f29d 100644 --- a/src/exports/roo-code.d.ts +++ b/src/exports/roo-code.d.ts @@ -354,6 +354,7 @@ type GlobalSettings = { } | undefined enhancementApiConfigId?: string | undefined + historyPreviewCollapsed?: boolean | undefined } type ClineMessage = { diff --git a/src/exports/types.ts b/src/exports/types.ts index 134f4fd0668..798036063a2 100644 --- a/src/exports/types.ts +++ b/src/exports/types.ts @@ -357,6 +357,7 @@ type GlobalSettings = { } | undefined enhancementApiConfigId?: string | undefined + historyPreviewCollapsed?: boolean | undefined } export type { GlobalSettings } diff --git a/src/schemas/index.ts b/src/schemas/index.ts index 8ebcdfc63a5..16d487308f7 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -565,6 +565,7 @@ export const globalSettingsSchema = z.object({ customModePrompts: customModePromptsSchema.optional(), customSupportPrompts: customSupportPromptsSchema.optional(), enhancementApiConfigId: z.string().optional(), + historyPreviewCollapsed: z.boolean().optional(), // Add the new setting }) export type GlobalSettings = z.infer @@ -641,6 +642,7 @@ const globalSettingsRecord: GlobalSettingsRecord = { customSupportPrompts: undefined, enhancementApiConfigId: undefined, cachedChromeHostUrl: undefined, + historyPreviewCollapsed: undefined, // Add to the record } export const GLOBAL_SETTINGS_KEYS = Object.keys(globalSettingsRecord) as Keys[] diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 83725bc5c36..a43c9b499eb 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -125,6 +125,7 @@ export interface WebviewMessage { | "maxReadFileLine" | "searchFiles" | "toggleApiConfigPin" + | "setHistoryPreviewCollapsed" // Add the missing type here text?: string disabled?: boolean askResponse?: ClineAskResponse diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 2ec4dfe8ead..ddd3e5f3428 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -65,9 +65,23 @@ "tooltip": "Cancel·la l'operació actual" }, "scrollToBottom": "Desplaça't al final del xat", + "about": "Genera, refactoritza i depura codi amb l'ajuda de la IA.
Consulta la nostra documentació per obtenir més informació.", "onboarding": " La vostra llista de tasques en aquest espai de treball està buida. Comença escrivint una tasca a continuació. \nNo esteu segur per on començar? \nMés informació sobre què pot fer Roo als documents.", + "rooTips": { + "boomerangTasks": { + "title": "Tasques Boomerang", + "description": "Divideix les tasques en parts més petites i manejables." + }, + "stickyModels": { + "title": "Models persistents", + "description": "Cada mode recorda el teu últim model utilitzat" + }, + "tools": { + "title": "Eines", + "description": "Permet que la IA resolgui problemes navegant per la web, executant ordres i molt més." + } + }, "selectMode": "Selecciona el mode d'interacció", - "selectApiConfig": "Selecciona la configuració de l'API", "enhancePrompt": "Millora la sol·licitud amb context addicional", "addImages": "Afegeix imatges al missatge", "sendMessage": "Envia el missatge", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index a1f947f997f..ce08c72f350 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -65,9 +65,23 @@ "tooltip": "Aktuelle Operation abbrechen" }, "scrollToBottom": "Zum Chat-Ende scrollen", + "about": "Generiere, überarbeite und debugge Code mit KI-Unterstützung.
Weitere Informationen findest du in unserer Dokumentation.", "onboarding": "Deine Aufgabenliste in diesem Arbeitsbereich ist leer. Beginne mit der Eingabe einer Aufgabe unten. Du bist dir nicht sicher, wie du anfangen sollst? Lies mehr darüber, was Roo für dich tun kann, in den Dokumenten.", + "rooTips": { + "boomerangTasks": { + "title": "Bumerang-Aufgaben", + "description": "Teile Aufgaben in kleinere, überschaubare Teile auf." + }, + "stickyModels": { + "title": "Sticky Models", + "description": "Jeder Modus merkt sich dein zuletzt verwendetes Modell" + }, + "tools": { + "title": "Tools", + "description": "Erlaube der KI, Probleme durch Surfen im Web, Ausführen von Befehlen und mehr zu lösen." + } + }, "selectMode": "Interaktionsmodus auswählen", - "selectApiConfig": "API-Konfiguration auswählen", "enhancePrompt": "Prompt mit zusätzlichem Kontext verbessern", "addImages": "Bilder zur Nachricht hinzufügen", "sendMessage": "Nachricht senden", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index b02cb12a324..504d2507685 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -67,6 +67,20 @@ "scrollToBottom": "Scroll to bottom of chat", "about": "Generate, refactor, and debug code with AI assistance.
Check out our documentation to learn more.", "onboarding": "Your task list in this workspace is empty.", + "rooTips": { + "boomerangTasks": { + "title": "Boomerang Tasks", + "description": "Split tasks into smaller, manageable parts." + }, + "stickyModels": { + "title": "Sticky Models", + "description": "Each mode remembers your last used model" + }, + "tools": { + "title": "Tools", + "description": "Allow the AI to solve problems by browsing the web, running commands, and more." + } + }, "selectMode": "Select mode for interaction", "selectApiConfig": "Select API configuration", "enhancePrompt": "Enhance prompt with additional context", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index 32cde2799b3..1342d95de39 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -65,9 +65,23 @@ "tooltip": "Cancelar la operación actual" }, "scrollToBottom": "Desplazarse al final del chat", + "about": "Genera, refactoriza y depura código con asistencia de IA.
Consulta nuestra documentación para obtener más información.", "onboarding": "Tu lista de tareas en este espacio de trabajo está vacía. Comienza escribiendo una tarea abajo. ¿No estás seguro cómo empezar? Lee más sobre lo que Roo puede hacer por ti en la documentación.", + "rooTips": { + "boomerangTasks": { + "title": "Tareas Boomerang", + "description": "Divide las tareas en partes más pequeñas y manejables." + }, + "stickyModels": { + "title": "Modelos persistentes", + "description": "Cada modo recuerda tu último modelo utilizado" + }, + "tools": { + "title": "Herramientas", + "description": "Permite que la IA resuelva problemas navegando por la web, ejecutando comandos y mucho más." + } + }, "selectMode": "Seleccionar modo de interacción", - "selectApiConfig": "Seleccionar configuración de API", "enhancePrompt": "Mejorar el mensaje con contexto adicional", "addImages": "Agregar imágenes al mensaje", "sendMessage": "Enviar mensaje", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 315538215f9..bdf05f394b5 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -65,9 +65,23 @@ "tooltip": "Annuler l'opération actuelle" }, "scrollToBottom": "Défiler jusqu'au bas du chat", + "about": "Générer, refactoriser et déboguer du code avec l'assistance de l'IA.
Consultez notre documentation pour en savoir plus.", "onboarding": "Grâce aux dernières avancées en matière de capacités de codage agent, je peux gérer des tâches complexes de développement logiciel étape par étape. Avec des outils qui me permettent de créer et d'éditer des fichiers, d'explorer des projets complexes, d'utiliser le navigateur et d'exécuter des commandes de terminal (après votre autorisation), je peux vous aider de manières qui vont au-delà de la complétion de code ou du support technique. Je peux même utiliser MCP pour créer de nouveaux outils et étendre mes propres capacités.", + "rooTips": { + "boomerangTasks": { + "title": "Tâches Boomerang", + "description": "Divisez les tâches en parties plus petites et gérables." + }, + "stickyModels": { + "title": "Modèles persistants", + "description": "Chaque mode se souvient de votre dernier modèle utilisé" + }, + "tools": { + "title": "Outils", + "description": "Permettez à l'IA de résoudre des problèmes en naviguant sur le Web, en exécutant des commandes, et plus encore." + } + }, "selectMode": "Sélectionner le mode d'interaction", - "selectApiConfig": "Sélectionner la configuration API", "enhancePrompt": "Améliorer la requête avec un contexte supplémentaire", "addImages": "Ajouter des images au message", "sendMessage": "Envoyer le message", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 09df88212d9..b0263b84130 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -65,9 +65,23 @@ "tooltip": "वर्तमान ऑपरेशन रद्द करें" }, "scrollToBottom": "चैट के निचले हिस्से तक स्क्रॉल करें", + "about": "एआई सहायता से कोड जेनरेट करें, रिफैक्टर करें और डिबग करें। अधिक जानने के लिए हमारे दस्तावेज़ देखें।", "onboarding": "एजेंटिक कोडिंग क्षमताओं में नवीनतम प्रगति के कारण, मैं जटिल सॉफ्टवेयर विकास कार्यों को चरण-दर-चरण संभाल सकता हूं। ऐसे उपकरणों के साथ जो मुझे फ़ाइलें बनाने और संपादित करने, जटिल प्रोजेक्ट का अन्वेषण करने, ब्राउज़र का उपयोग करने और टर्मिनल कमांड (आपकी अनुमति के बाद) निष्पादित करने की अनुमति देते हैं, मैं आपकी मदद कोड पूर्णता या तकनीकी समर्थन से परे तरीकों से कर सकता हूं। मैं अपनी क्षमताओं का विस्तार करने और नए उपकरण बनाने के लिए MCP का भी उपयोग कर सकता हूं।", + "rooTips": { + "boomerangTasks": { + "title": "बूमरैंग कार्य", + "description": "कार्यों को छोटे, प्रबंधनीय भागों में विभाजित करें।" + }, + "stickyModels": { + "title": "चिपचिपे मॉडल", + "description": "प्रत्येक मोड आपके अंतिम उपयोग किए गए मॉडल को याद रखता है" + }, + "tools": { + "title": "उपकरण", + "description": "एआई को वेब ब्राउज़ करके, कमांड चलाकर और अधिक समस्याओं को हल करने की अनुमति दें।" + } + }, "selectMode": "इंटरैक्शन मोड चुनें", - "selectApiConfig": "API कॉन्फ़िगरेशन चुनें", "enhancePrompt": "अतिरिक्त संदर्भ के साथ प्रॉम्प्ट बढ़ाएँ", "addImages": "संदेश में चित्र जोड़ें", "sendMessage": "संदेश भेजें", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 38dd7d49513..8d9dadaf7a5 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -65,9 +65,23 @@ "tooltip": "Annulla l'operazione corrente" }, "scrollToBottom": "Scorri fino alla fine della chat", + "about": "Genera, refactor e debug del codice con l'assistenza dell'IA.
Consulta la nostra documentazione per saperne di più.", "onboarding": "Grazie alle più recenti innovazioni nelle capacità di codifica agentica, posso gestire complesse attività di sviluppo software passo dopo passo. Con strumenti che mi permettono di creare e modificare file, esplorare progetti complessi, utilizzare il browser ed eseguire comandi da terminale (dopo la tua autorizzazione), posso aiutarti in modi che vanno oltre il completamento del codice o il supporto tecnico. Posso persino usare MCP per creare nuovi strumenti ed estendere le mie capacità.", + "rooTips": { + "boomerangTasks": { + "title": "Attività Boomerang", + "description": "Dividi le attività in parti più piccole e gestibili." + }, + "stickyModels": { + "title": "Modelli persistenti", + "description": "Ogni modalità ricorda il tuo ultimo modello utilizzato" + }, + "tools": { + "title": "Strumenti", + "description": "Consenti all'IA di risolvere i problemi navigando sul Web, eseguendo comandi e altro ancora." + } + }, "selectMode": "Seleziona modalità di interazione", - "selectApiConfig": "Seleziona configurazione API", "enhancePrompt": "Migliora prompt con contesto aggiuntivo", "addImages": "Aggiungi immagini al messaggio", "sendMessage": "Invia messaggio", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 39ceb74099f..c3f06d5c869 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -65,9 +65,23 @@ "tooltip": "現在の操作をキャンセル" }, "scrollToBottom": "チャットの最下部にスクロール", + "about": "AI支援でコードを生成、リファクタリング、デバッグします。詳細については、ドキュメントをご覧ください。", "onboarding": "最新のエージェント型コーディング能力の進歩により、複雑なソフトウェア開発タスクをステップバイステップで処理できます。ファイルの作成や編集、複雑なプロジェクトの探索、ブラウザの使用、ターミナルコマンドの実行(許可後)を可能にするツールにより、コード補完や技術サポート以上の方法であなたをサポートできます。MCPを使用して新しいツールを作成し、自分の能力を拡張することもできます。", + "rooTips": { + "boomerangTasks": { + "title": "ブーメランタスク", + "description": "タスクをより小さく、管理しやすい部分に分割します。" + }, + "stickyModels": { + "title": "スティッキーモデル", + "description": "各モードは、最後に使用したモデルを記憶します" + }, + "tools": { + "title": "ツール", + "description": "AIがWebの閲覧、コマンドの実行などによって問題を解決できるようにします。" + } + }, "selectMode": "対話モードを選択", - "selectApiConfig": "API設定を選択", "enhancePrompt": "追加コンテキストでプロンプトを強化", "addImages": "メッセージに画像を追加", "sendMessage": "メッセージを送信", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index d37fff02d14..09ba01de182 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -65,9 +65,23 @@ "tooltip": "현재 작업 취소" }, "scrollToBottom": "채팅 하단으로 스크롤", + "about": "AI 지원으로 코드를 생성, 리팩터링 및 디버깅합니다. 자세한 내용은 문서를 확인하세요.", "onboarding": "이 작업 공간의 작업 목록이 비어 있습니다. 아래에 작업을 입력하여 시작하세요. 어떻게 시작해야 할지 모르겠나요? Roo가 무엇을 할 수 있는지 문서에서 자세히 알아보세요.", + "rooTips": { + "boomerangTasks": { + "title": "부메랑 작업", + "description": "작업을 더 작고 관리하기 쉬운 부분으로 나눕니다." + }, + "stickyModels": { + "title": "고정 모델", + "description": "각 모드는 마지막으로 사용한 모델을 기억합니다." + }, + "tools": { + "title": "도구", + "description": "AI가 웹 탐색, 명령 실행 등으로 문제를 해결하도록 허용합니다." + } + }, "selectMode": "상호작용 모드 선택", - "selectApiConfig": "API 구성 선택", "enhancePrompt": "추가 컨텍스트로 프롬프트 향상", "addImages": "메시지에 이미지 추가", "sendMessage": "메시지 보내기", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 239c1f09c18..964c13e09fb 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -65,9 +65,23 @@ "tooltip": "Anuluj bieżącą operację" }, "scrollToBottom": "Przewiń do dołu czatu", + "about": "Generuj, refaktoryzuj i debuguj kod z pomocą sztucznej inteligencji.
Sprawdź naszą dokumentację, aby dowiedzieć się więcej.", "onboarding": "Twoja lista zadań w tym obszarze roboczym jest pusta. Zacznij od wpisania zadania poniżej. Nie wiesz, jak zacząć? Przeczytaj więcej o tym, co Roo może dla Ciebie zrobić w dokumentacji.", + "rooTips": { + "boomerangTasks": { + "title": "Zadania bumerangowe", + "description": "Podziel zadania na mniejsze, łatwiejsze do zarządzania części." + }, + "stickyModels": { + "title": "Modele przyklejone", + "description": "Każdy tryb zapamiętuje ostatnio używany model" + }, + "tools": { + "title": "Narzędzia", + "description": "Pozwól sztucznej inteligencji rozwiązywać problemy, przeglądając sieć, uruchamiając polecenia i nie tylko." + } + }, "selectMode": "Wybierz tryb interakcji", - "selectApiConfig": "Wybierz konfigurację API", "enhancePrompt": "Ulepsz podpowiedź dodatkowym kontekstem", "addImages": "Dodaj obrazy do wiadomości", "sendMessage": "Wyślij wiadomość", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index 1f1d620f2c4..9fc05e9eb02 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -65,9 +65,23 @@ "tooltip": "Cancelar a operação atual" }, "scrollToBottom": "Rolar para o final do chat", + "about": "Gere, refatore e depure código com assistência de IA.
Confira nossa documentação para saber mais.", "onboarding": "Sua lista de tarefas neste espaço de trabalho está vazia. Comece digitando uma tarefa abaixo. Não sabe como começar? Leia mais sobre o que o Roo pode fazer por você nos documentos.", + "rooTips": { + "boomerangTasks": { + "title": "Tarefas Bumerangue", + "description": "Divida as tarefas em partes menores e gerenciáveis." + }, + "stickyModels": { + "title": "Modelos Persistentes", + "description": "Cada modo lembra seu último modelo usado" + }, + "tools": { + "title": "Ferramentas", + "description": "Permita que a IA resolva problemas navegando na web, executando comandos e muito mais." + } + }, "selectMode": "Selecionar modo de interação", - "selectApiConfig": "Selecionar configuração de API", "enhancePrompt": "Aprimorar prompt com contexto adicional", "addImages": "Adicionar imagens à mensagem", "sendMessage": "Enviar mensagem", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index c02620ea25c..dae2adbed2b 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -65,9 +65,23 @@ "tooltip": "Mevcut işlemi iptal et" }, "scrollToBottom": "Sohbetin altına kaydır", + "about": "AI yardımıyla kod oluşturun, yeniden düzenleyin ve hatalarını ayıklayın.
Daha fazla bilgi edinmek için belgelerimize göz atın.", "onboarding": "Bu çalışma alanındaki görev listeniz boş. Aşağıya bir görev yazarak başlayın. Nasıl başlayacağınızdan emin değil misiniz? Roo'nun sizin için neler yapabileceği hakkında daha fazla bilgiyi belgelerde okuyun.", + "rooTips": { + "boomerangTasks": { + "title": "Bumerang Görevleri", + "description": "Görevleri daha küçük, yönetilebilir parçalara ayırın." + }, + "stickyModels": { + "title": "Yapışkan Modeller", + "description": "Her mod en son kullandığınız modeli hatırlar" + }, + "tools": { + "title": "Araçlar", + "description": "AI'nın web'e göz atarak, komutlar çalıştırarak ve daha fazlasını yaparak sorunları çözmesine izin verin." + } + }, "selectMode": "Etkileşim modunu seçin", - "selectApiConfig": "API yapılandırmasını seçin", "enhancePrompt": "Ek bağlamla istemi geliştir", "addImages": "Mesaja resim ekle", "sendMessage": "Mesaj gönder", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index cdf77f48f56..f9dfbdfc641 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -65,9 +65,23 @@ "tooltip": "Hủy thao tác hiện tại" }, "scrollToBottom": "Cuộn xuống cuối cuộc trò chuyện", + "about": "Tạo, tái cấu trúc và gỡ lỗi mã bằng sự hỗ trợ của AI.
Kiểm tra tài liệu của chúng tôi để tìm hiểu thêm.", "onboarding": "Danh sách nhiệm vụ của bạn trong không gian làm việc này trống. Bắt đầu bằng cách nhập nhiệm vụ bên dưới. Bạn không chắc chắn nên bắt đầu như thế nào? Đọc thêm về những gì Roo có thể làm cho bạn trong tài liệu.", + "rooTips": { + "boomerangTasks": { + "title": "Nhiệm vụ Boomerang", + "description": "Chia nhỏ các nhiệm vụ thành các phần nhỏ hơn, dễ quản lý hơn." + }, + "stickyModels": { + "title": "Mô hình dính", + "description": "Mỗi chế độ ghi nhớ mô hình bạn đã sử dụng gần đây nhất" + }, + "tools": { + "title": "Công cụ", + "description": "Cho phép AI giải quyết vấn đề bằng cách duyệt web, chạy lệnh, v.v." + } + }, "selectMode": "Chọn chế độ tương tác", - "selectApiConfig": "Chọn cấu hình API", "enhancePrompt": "Nâng cao yêu cầu với ngữ cảnh bổ sung", "addImages": "Thêm hình ảnh vào tin nhắn", "sendMessage": "Gửi tin nhắn", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 928dcc047a9..e84ab132d2d 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -65,9 +65,23 @@ "tooltip": "取消当前操作" }, "scrollToBottom": "滚动到聊天底部", + "about": "通过 AI 辅助生成、重构和调试代码。
查看我们的 文档 了解更多信息。", "onboarding": "此工作区中的任务列表为空。 请在下方输入任务开始。 不确定如何开始? 在 文档 中阅读更多关于 Roo 可以为您做什么的信息。", + "rooTips": { + "boomerangTasks": { + "title": "任务拆分", + "description": "将任务拆分为更小、更易于管理的部分。" + }, + "stickyModels": { + "title": "增强导向模式", + "description": "每个模式都会记住您上次使用的模型" + }, + "tools": { + "title": "工具", + "description": "允许 AI 通过浏览网络、运行命令等方式解决问题。" + } + }, "selectMode": "选择交互模式", - "selectApiConfig": "选择API配置", "enhancePrompt": "增强提示词", "addImages": "添加图片到消息", "sendMessage": "发送消息", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 305d012dc6d..66d5a53fa15 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -65,9 +65,23 @@ "tooltip": "取消目前操作" }, "scrollToBottom": "捲動至對話框底部", + "about": "透過 AI 輔助產生、重構和偵錯程式碼。
查看我們的 說明文件 以瞭解更多資訊。", "onboarding": "您在此工作區中的工作清單是空的。 請在下方輸入工作以開始。 不確定如何開始? 在 說明文件 中閱讀更多關於 Roo 能為您做什麼的資訊。", + "rooTips": { + "boomerangTasks": { + "title": "任務拆分", + "description": "將任務拆分為更小、更易於管理的部分。" + }, + "stickyModels": { + "title": "增強導向模式", + "description": "每個模式都會記住您上次使用的模型" + }, + "tools": { + "title": "工具", + "description": "允許 AI 透過瀏覽網路、執行命令等方式解決問題。" + } + }, "selectMode": "選擇互動模式", - "selectApiConfig": "選擇 API 設定", "enhancePrompt": "使用額外內容增強提示", "addImages": "新增圖片到訊息中", "sendMessage": "傳送訊息", From f40f516ed9f71da34ea0425e87108242529256c4 Mon Sep 17 00:00:00 2001 From: Sacha Sayan Date: Fri, 25 Apr 2025 11:37:14 -0400 Subject: [PATCH 4/5] Minimal 'tasks' language. --- webview-ui/src/i18n/locales/ca/history.json | 2 +- webview-ui/src/i18n/locales/de/history.json | 2 +- webview-ui/src/i18n/locales/en/history.json | 2 +- webview-ui/src/i18n/locales/es/history.json | 2 +- webview-ui/src/i18n/locales/fr/history.json | 2 +- webview-ui/src/i18n/locales/hi/history.json | 2 +- webview-ui/src/i18n/locales/it/history.json | 2 +- webview-ui/src/i18n/locales/ko/history.json | 2 +- webview-ui/src/i18n/locales/pl/history.json | 2 +- webview-ui/src/i18n/locales/pt-BR/history.json | 2 +- webview-ui/src/i18n/locales/tr/history.json | 2 +- webview-ui/src/i18n/locales/vi/history.json | 2 +- webview-ui/src/i18n/locales/zh-CN/history.json | 2 +- webview-ui/src/i18n/locales/zh-TW/history.json | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/webview-ui/src/i18n/locales/ca/history.json b/webview-ui/src/i18n/locales/ca/history.json index 6bf40b3d838..9efa263823d 100644 --- a/webview-ui/src/i18n/locales/ca/history.json +++ b/webview-ui/src/i18n/locales/ca/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Tasques recents", + "recentTasks": "Tasques", "viewAll": "Veure tot", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Cau: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/de/history.json b/webview-ui/src/i18n/locales/de/history.json index f85243c886f..247d09a8924 100644 --- a/webview-ui/src/i18n/locales/de/history.json +++ b/webview-ui/src/i18n/locales/de/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Jüngste Aufgaben", + "recentTasks": "Aufgaben", "viewAll": "Alle anzeigen", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Cache: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/en/history.json b/webview-ui/src/i18n/locales/en/history.json index 5e785fd5444..19d481fe4b7 100644 --- a/webview-ui/src/i18n/locales/en/history.json +++ b/webview-ui/src/i18n/locales/en/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Recent Tasks", + "recentTasks": "Tasks", "viewAll": "View All Tasks", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Cache: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/es/history.json b/webview-ui/src/i18n/locales/es/history.json index 7a0d93ce8d9..d7c65ef6b15 100644 --- a/webview-ui/src/i18n/locales/es/history.json +++ b/webview-ui/src/i18n/locales/es/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Tareas recientes", + "recentTasks": "Tareas", "viewAll": "Ver todas", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Caché: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/fr/history.json b/webview-ui/src/i18n/locales/fr/history.json index 76b1f8cc3fb..4e33048753a 100644 --- a/webview-ui/src/i18n/locales/fr/history.json +++ b/webview-ui/src/i18n/locales/fr/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Tâches récentes", + "recentTasks": "Tâches", "viewAll": "Voir tout", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Cache: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/hi/history.json b/webview-ui/src/i18n/locales/hi/history.json index dcadfbe5e4c..58373f95261 100644 --- a/webview-ui/src/i18n/locales/hi/history.json +++ b/webview-ui/src/i18n/locales/hi/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "हाल के कार्य", + "recentTasks": "कार्य", "viewAll": "सभी देखें", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "कैश: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/it/history.json b/webview-ui/src/i18n/locales/it/history.json index 9f0dc2ce757..c56f8492d3d 100644 --- a/webview-ui/src/i18n/locales/it/history.json +++ b/webview-ui/src/i18n/locales/it/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Compiti recenti", + "recentTasks": "Compiti", "viewAll": "Vedi tutto", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Cache: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/ko/history.json b/webview-ui/src/i18n/locales/ko/history.json index dd5042540ad..a35cc9b1f13 100644 --- a/webview-ui/src/i18n/locales/ko/history.json +++ b/webview-ui/src/i18n/locales/ko/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "최근 작업", + "recentTasks": "작업", "viewAll": "모두 보기", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "캐시: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/pl/history.json b/webview-ui/src/i18n/locales/pl/history.json index d66c4b349ab..f775b04de35 100644 --- a/webview-ui/src/i18n/locales/pl/history.json +++ b/webview-ui/src/i18n/locales/pl/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Ostatnie zadania", + "recentTasks": "Zadania", "viewAll": "Zobacz wszystkie", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Pamięć podręczna: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/pt-BR/history.json b/webview-ui/src/i18n/locales/pt-BR/history.json index 2c25fe6e59d..58fdb7e6ed9 100644 --- a/webview-ui/src/i18n/locales/pt-BR/history.json +++ b/webview-ui/src/i18n/locales/pt-BR/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Tarefas recentes", + "recentTasks": "Tarefas", "viewAll": "Ver todas", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Cache: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/tr/history.json b/webview-ui/src/i18n/locales/tr/history.json index a29107ef76d..672659b90d2 100644 --- a/webview-ui/src/i18n/locales/tr/history.json +++ b/webview-ui/src/i18n/locales/tr/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Son Görevler", + "recentTasks": "Görevler", "viewAll": "Tümünü Gör", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "Önbellek: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/vi/history.json b/webview-ui/src/i18n/locales/vi/history.json index 3d3565c2e88..00154d47c3a 100644 --- a/webview-ui/src/i18n/locales/vi/history.json +++ b/webview-ui/src/i18n/locales/vi/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "Nhiệm vụ gần đây", + "recentTasks": "Nhiệm vụ", "viewAll": "Xem tất cả", "tokens": "Token: ↑{{in}} ↓{{out}}", "cache": "Bộ nhớ đệm: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/zh-CN/history.json b/webview-ui/src/i18n/locales/zh-CN/history.json index 68cffd73892..43c362aaa14 100644 --- a/webview-ui/src/i18n/locales/zh-CN/history.json +++ b/webview-ui/src/i18n/locales/zh-CN/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "最近任务", + "recentTasks": "任务", "viewAll": "查看全部", "tokens": "Token用量: ↑{{in}} ↓{{out}}", "cache": "缓存操作: +{{writes}} → {{reads}}", diff --git a/webview-ui/src/i18n/locales/zh-TW/history.json b/webview-ui/src/i18n/locales/zh-TW/history.json index f3a009022c8..d234ef6b3dd 100644 --- a/webview-ui/src/i18n/locales/zh-TW/history.json +++ b/webview-ui/src/i18n/locales/zh-TW/history.json @@ -1,5 +1,5 @@ { - "recentTasks": "最近的工作", + "recentTasks": "工作", "viewAll": "檢視全部", "tokens": "Tokens: ↑{{in}} ↓{{out}}", "cache": "快取:+{{writes}} → {{reads}}", From 5506882554db856e51727dd2281e33af75c810bb Mon Sep 17 00:00:00 2001 From: Sacha Sayan Date: Fri, 25 Apr 2025 12:16:58 -0400 Subject: [PATCH 5/5] Toggle revision. --- webview-ui/src/components/chat/ChatView.tsx | 32 ++++++++++-- .../src/components/history/HistoryPreview.tsx | 50 ++++++------------- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 12f213a2649..6a8aa661805 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -80,10 +80,23 @@ const ChatViewComponent: React.ForwardRefRenderFunction { + const newState = !isExpanded + setIsExpanded(newState) + // Send message to extension to persist the new collapsed state + vscode.postMessage({ type: "setHistoryPreviewCollapsed", bool: !newState }) + }, [isExpanded]) + //const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined const task = useMemo(() => messages.at(0), [messages]) // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see Cline.abort) const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages]) @@ -1198,6 +1211,17 @@ const ChatViewComponent: React.ForwardRefRenderFunction + {/* Moved Task Bar Header Here */} + {tasks.length !== 0 && ( +
+
+ {tasks.length < 10 && ( + {t("history:recentTasks")} + )} + +
+
+ )} {task ? ( <> )} - {/* Show the task history if there are any for this workspace. */} - {taskHistory.length > 0 && } + {/* Show the task history preview if expanded and tasks exist */} + {taskHistory.length > 0 && isExpanded && } {/* Finally, if there less than 3 tasks, we can show the tips */} - {tasks.length < 3 && 0)} />} + {tasks.length < 3 && isExpanded && ( + 0)} /> + )}
)} diff --git a/webview-ui/src/components/history/HistoryPreview.tsx b/webview-ui/src/components/history/HistoryPreview.tsx index 21a1f0bbd72..3a01ce534c9 100644 --- a/webview-ui/src/components/history/HistoryPreview.tsx +++ b/webview-ui/src/components/history/HistoryPreview.tsx @@ -1,52 +1,23 @@ -import { memo, useState, useCallback } from "react" +import { memo } from "react" import { vscode } from "@/utils/vscode" import { formatLargeNumber, formatDate } from "@/utils/format" import { Button } from "@/components/ui" import { useAppTranslation } from "@src/i18n/TranslationContext" -import { useExtensionState } from "@src/context/ExtensionStateContext" import { CopyButton } from "./CopyButton" import { useTaskSearch } from "./useTaskSearch" import { Trans } from "react-i18next" import { Coins } from "lucide-react" -type HistoryPreviewProps = { - showHistoryView: () => void -} -const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => { +const HistoryPreview = () => { const { tasks, showAllWorkspaces } = useTaskSearch() - const { historyPreviewCollapsed } = useExtensionState() // Will add this state later const { t } = useAppTranslation() - // Initialize expanded state based on the persisted setting (default to expanded if undefined) - const [isExpanded, setIsExpanded] = useState( - historyPreviewCollapsed === undefined ? true : !historyPreviewCollapsed, - ) - - const toggleExpanded = useCallback(() => { - const newState = !isExpanded - setIsExpanded(newState) - // Send message to extension to persist the new collapsed state - vscode.postMessage({ type: "setHistoryPreviewCollapsed", bool: !newState }) - }, [isExpanded]) return ( <>
- {tasks.length !== 0 && ( -
-
- - {t("history:recentTasks")} -
- {/* Keep the history button, but maybe it should just show the full view? Or remove it if header is clicked? Let's keep it for now. */} - -
- )} - {tasks.length === 0 && ( <>

@@ -65,14 +36,21 @@ const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => { />

- )} - {tasks.length !== 0 && isExpanded && ( + {tasks.length !== 0 && ( <> {tasks.slice(0, 3).map((item) => (
{
))} - {/* Add a "View All" link below the preview list when expanded */} + {/* The link to show history view will be moved to ChatView */}
showHistoryView()}> + onClick={() => { + /* TODO: Implement or remove */ + }}> {t("history:viewAll")} ({tasks.length})