From 8353f03cd37fedccffc02e96c5b6b95d6abd8467 Mon Sep 17 00:00:00 2001 From: Bruno Bergher Date: Mon, 10 Nov 2025 13:01:19 +0000 Subject: [PATCH 1/7] First pass at custom Button component --- .../chat/AutoApprovedRequestLimitWarning.tsx | 6 ++-- .../src/components/chat/BrowserSessionRow.tsx | 10 +++---- webview-ui/src/components/chat/ChatView.tsx | 22 +++++++------- .../src/components/chat/CodeIndexPopover.tsx | 13 ++++---- .../chat/checkpoints/CheckpointMenu.tsx | 2 +- webview-ui/src/components/cloud/CloudView.tsx | 20 +++++-------- .../components/common/VSCodeButtonLink.tsx | 30 ++++++++++++------- .../src/components/history/HistoryView.tsx | 4 +-- .../marketplace/MarketplaceView.tsx | 2 +- .../components/MarketplaceItemCard.tsx | 2 +- webview-ui/src/components/mcp/McpView.tsx | 9 +++--- webview-ui/src/components/modes/ModesView.tsx | 10 +++---- .../components/settings/ApiConfigManager.tsx | 2 +- .../components/settings/AutoApproveToggle.tsx | 2 +- .../components/settings/BrowserSettings.tsx | 17 ++++++++--- .../components/settings/PromptsSettings.tsx | 2 +- .../src/components/settings/SettingsView.tsx | 2 +- .../src/components/settings/providers/Roo.tsx | 9 +++--- .../providers/__tests__/HuggingFace.spec.tsx | 7 ++++- webview-ui/src/components/ui/button.tsx | 12 ++++---- .../src/components/welcome/WelcomeView.tsx | 7 +++-- 21 files changed, 103 insertions(+), 87 deletions(-) diff --git a/webview-ui/src/components/chat/AutoApprovedRequestLimitWarning.tsx b/webview-ui/src/components/chat/AutoApprovedRequestLimitWarning.tsx index 6f019a84c8c..c7744f1bfdb 100644 --- a/webview-ui/src/components/chat/AutoApprovedRequestLimitWarning.tsx +++ b/webview-ui/src/components/chat/AutoApprovedRequestLimitWarning.tsx @@ -1,10 +1,10 @@ import React, { memo, useState } from "react" -import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" import { Trans } from "react-i18next" import type { ClineMessage } from "@roo-code/types" import { vscode } from "@src/utils/vscode" +import { Button } from "@src/components/ui" type AutoApprovedRequestLimitWarningProps = { message: ClineMessage @@ -50,7 +50,7 @@ export const AutoApprovedRequestLimitWarning = memo(({ message }: AutoApprovedRe
- { e.preventDefault() @@ -58,7 +58,7 @@ export const AutoApprovedRequestLimitWarning = memo(({ message }: AutoApprovedRe vscode.postMessage({ type: "askResponse", askResponse: "yesButtonClicked" }) }}> - + ) diff --git a/webview-ui/src/components/chat/BrowserSessionRow.tsx b/webview-ui/src/components/chat/BrowserSessionRow.tsx index c23b79f568a..57cb0cf2432 100644 --- a/webview-ui/src/components/chat/BrowserSessionRow.tsx +++ b/webview-ui/src/components/chat/BrowserSessionRow.tsx @@ -2,7 +2,6 @@ import React, { memo, useEffect, useMemo, useRef, useState } from "react" import { useSize } from "react-use" import deepEqual from "fast-deep-equal" import { useTranslation } from "react-i18next" -import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" import type { ClineMessage } from "@roo-code/types" @@ -10,6 +9,7 @@ import { BrowserAction, BrowserActionResult, ClineSayBrowserAction } from "@roo/ import { vscode } from "@src/utils/vscode" import { useExtensionState } from "@src/context/ExtensionStateContext" +import { Button } from "@src/components/ui" import CodeBlock, { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock" import { ChatRowContent } from "./ChatRow" @@ -372,16 +372,16 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => { {t("chat:browser.navigation.step", { current: currentPageIndex + 1, total: pages.length })}
- setCurrentPageIndex((i) => i - 1)}> {t("chat:browser.navigation.previous")} - - +
)} diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 19b7613b3eb..42194ec601e 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -3,7 +3,7 @@ import { useDeepCompareEffect, useEvent, useMount } from "react-use" import debounce from "debounce" import { Virtuoso, type VirtuosoHandle } from "react-virtuoso" import removeMd from "remove-markdown" -import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react" +import { VSCodeLink } from "@vscode/webview-ui-toolkit/react" import useSound from "use-sound" import { LRUCache } from "lru-cache" import { Trans, useTranslation } from "react-i18next" @@ -37,7 +37,7 @@ import { useExtensionState } from "@src/context/ExtensionStateContext" import { useSelectedModel } from "@src/components/ui/hooks/useSelectedModel" import RooHero from "@src/components/welcome/RooHero" import RooTips from "@src/components/welcome/RooTips" -import { StandardTooltip } from "@src/components/ui" +import { StandardTooltip, Button } from "@src/components/ui" import { useAutoApprovalState } from "@src/hooks/useAutoApprovalState" import { useAutoApprovalToggles } from "@src/hooks/useAutoApprovalToggles" import { CloudUpsellDialog } from "@src/components/cloud/CloudUpsellDialog" @@ -1860,15 +1860,15 @@ const ChatViewComponent: React.ForwardRefRenderFunction {showScrollToBottom ? ( - { scrollToBottomSmooth() disableAutoScrollRef.current = false }}> - + ) : ( <> @@ -1895,13 +1895,13 @@ const ChatViewComponent: React.ForwardRefRenderFunction - handlePrimaryButtonClick(inputValue, selectedImages)}> {primaryButtonText} - + )} {(secondaryButtonText || isStreaming) && ( @@ -1917,13 +1917,13 @@ const ChatViewComponent: React.ForwardRefRenderFunction - handleSecondaryButtonClick(inputValue, selectedImages)}> {isStreaming ? t("chat:cancel.title") : secondaryButtonText} - + )} diff --git a/webview-ui/src/components/chat/CodeIndexPopover.tsx b/webview-ui/src/components/chat/CodeIndexPopover.tsx index 42fe9498e70..70a13377300 100644 --- a/webview-ui/src/components/chat/CodeIndexPopover.tsx +++ b/webview-ui/src/components/chat/CodeIndexPopover.tsx @@ -41,6 +41,7 @@ import { PopoverContent, Slider, StandardTooltip, + Button, } from "@src/components/ui" import { useRooPortal } from "@src/components/ui/hooks/useRooPortal" import { useEscapeKey } from "@src/hooks/useEscapeKey" @@ -1387,11 +1388,11 @@ export const CodeIndexPopover: React.FC = ({ {currentSettings.codebaseIndexEnabled && (indexingStatus.systemStatus === "Error" || indexingStatus.systemStatus === "Standby") && ( - vscode.postMessage({ type: "startIndexing" })} disabled={saveStatus === "saving" || hasUnsavedChanges}> {t("settings:codeIndex.startIndexingButton")} - + )} {currentSettings.codebaseIndexEnabled && @@ -1399,9 +1400,9 @@ export const CodeIndexPopover: React.FC = ({ indexingStatus.systemStatus === "Error") && ( - + @@ -1426,13 +1427,13 @@ export const CodeIndexPopover: React.FC = ({ )} - {saveStatus === "saving" ? t("settings:codeIndex.saving") : t("settings:codeIndex.saveSettings")} - + {/* Save Status Messages */} diff --git a/webview-ui/src/components/chat/checkpoints/CheckpointMenu.tsx b/webview-ui/src/components/chat/checkpoints/CheckpointMenu.tsx index 0e65cfa5cdc..4895d05b3a0 100644 --- a/webview-ui/src/components/chat/checkpoints/CheckpointMenu.tsx +++ b/webview-ui/src/components/chat/checkpoints/CheckpointMenu.tsx @@ -135,7 +135,7 @@ export const CheckpointMenu = ({ ts, commitHash, checkpoint, onOpenChange }: Che ) : ( <> + ) : ( @@ -281,9 +275,9 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone, orga
{renderCloudBenefitsContent(t)}
{!authInProgress && ( - + )} {/* Manual entry section */} diff --git a/webview-ui/src/components/common/VSCodeButtonLink.tsx b/webview-ui/src/components/common/VSCodeButtonLink.tsx index d0cd6b1c977..ee56ee4f7f8 100644 --- a/webview-ui/src/components/common/VSCodeButtonLink.tsx +++ b/webview-ui/src/components/common/VSCodeButtonLink.tsx @@ -1,19 +1,27 @@ import React from "react" -import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" +import { Button } from "@src/components/ui" interface VSCodeButtonLinkProps { href: string children: React.ReactNode + appearance?: "primary" | "secondary" [key: string]: any } -export const VSCodeButtonLink = ({ href, children, ...props }: VSCodeButtonLinkProps) => ( - - {children} - -) +export const VSCodeButtonLink = ({ href, children, appearance, ...props }: VSCodeButtonLinkProps) => { + // Map appearance to variant for the new Button component + const variant = appearance === "primary" ? "primary" : appearance === "secondary" ? "secondary" : undefined + + return ( + + + + ) +} diff --git a/webview-ui/src/components/history/HistoryView.tsx b/webview-ui/src/components/history/HistoryView.tsx index e7b574c490c..21b083a7b99 100644 --- a/webview-ui/src/components/history/HistoryView.tsx +++ b/webview-ui/src/components/history/HistoryView.tsx @@ -91,7 +91,7 @@ const HistoryView = ({ onDone }: HistoryViewProps) => { : `${t("history:enterSelectionMode")}` }> - diff --git a/webview-ui/src/components/marketplace/MarketplaceView.tsx b/webview-ui/src/components/marketplace/MarketplaceView.tsx index abfcf87cc5c..0d66be48afd 100644 --- a/webview-ui/src/components/marketplace/MarketplaceView.tsx +++ b/webview-ui/src/components/marketplace/MarketplaceView.tsx @@ -103,7 +103,7 @@ export function MarketplaceView({ stateManager, onDone, targetTab }: Marketplace

{t("marketplace:title")}

- {server.status === "connecting" ? t("mcp:serverStatus.retrying") : t("mcp:serverStatus.retryConnection")} - + )} @@ -554,7 +553,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM - diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index 1107eb44e10..2504fe914b9 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -1228,7 +1228,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
-
@@ -1682,7 +1682,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { {t("prompts:createModeDialog.buttons.cancel")}
{testResult && (
)} ({ // Mock the UI components vi.mock("@src/components/ui", () => ({ + Button: ({ children, onClick, variant, ...rest }: any) => ( + + ), Select: ({ children }: any) =>
{children}
, SelectContent: ({ children }: any) =>
{children}
, SelectItem: ({ children }: any) =>
{children}
, @@ -190,7 +195,7 @@ describe("HuggingFace Component", () => { ) // Check that the API key button is rendered - const apiKeyButton = screen.getByTestId("vscode-button") + const apiKeyButton = screen.getByTestId("button") expect(apiKeyButton).toBeInTheDocument() expect(apiKeyButton).toHaveTextContent("Get Hugging Face API Key") }) diff --git a/webview-ui/src/components/ui/button.tsx b/webview-ui/src/components/ui/button.tsx index 015cdabda00..2d4bf6379ba 100644 --- a/webview-ui/src/components/ui/button.tsx +++ b/webview-ui/src/components/ui/button.tsx @@ -5,17 +5,17 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xs text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer active:opacity-80", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer active:opacity-80", { variants: { variant: { - default: "border border-vscode-input-border bg-primary text-primary-foreground hover:bg-primary/90", - destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: - "border border-vscode-input-border bg-transparent hover:bg-accent hover:text-accent-foreground", + primary: "border border-vscode-input-border bg-primary text-primary-foreground hover:bg-primary/90", secondary: "border border-vscode-input-border bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", + destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-vscode-input-border bg-transparent hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", combobox: "border border-vscode-dropdown-border focus-visible:border-vscode-focusBorder bg-vscode-dropdown-background hover:bg-transparent text-vscode-dropdown-foreground font-normal", @@ -28,7 +28,7 @@ const buttonVariants = cva( }, }, defaultVariants: { - variant: "default", + variant: "secondary", size: "default", }, }, diff --git a/webview-ui/src/components/welcome/WelcomeView.tsx b/webview-ui/src/components/welcome/WelcomeView.tsx index e2af5c93d41..395e97bca8b 100644 --- a/webview-ui/src/components/welcome/WelcomeView.tsx +++ b/webview-ui/src/components/welcome/WelcomeView.tsx @@ -1,7 +1,7 @@ import { useCallback, useState, useEffect } from "react" import knuthShuffle from "knuth-shuffle-seeded" import { Trans } from "react-i18next" -import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react" +import { VSCodeLink } from "@vscode/webview-ui-toolkit/react" import posthog from "posthog-js" import type { ProviderSettings } from "@roo-code/types" @@ -13,6 +13,7 @@ import { vscode } from "@src/utils/vscode" import { useAppTranslation } from "@src/i18n/TranslationContext" import { getRequestyAuthUrl, getOpenRouterAuthUrl } from "@src/oauth/urls" import { telemetryClient } from "@src/utils/TelemetryClient" +import { Button } from "@src/components/ui" import ApiOptions from "../settings/ApiOptions" import { Tab, TabContent } from "../common/Tab" @@ -198,9 +199,9 @@ const WelcomeView = () => { {t("welcome:importSettings")}
- + {errorMessage &&
{errorMessage}
} From bcf79e2291c45eca7a4e971c57ef89cf59f45ca5 Mon Sep 17 00:00:00 2001 From: Bruno Bergher Date: Mon, 10 Nov 2025 13:02:32 +0000 Subject: [PATCH 2/7] Not _that_ rounded --- webview-ui/src/components/ui/button.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/ui/button.tsx b/webview-ui/src/components/ui/button.tsx index 2d4bf6379ba..3a38cb8946d 100644 --- a/webview-ui/src/components/ui/button.tsx +++ b/webview-ui/src/components/ui/button.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer active:opacity-80", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xl text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer active:opacity-80", { variants: { variant: { From 9ec0bff47f668bd04fe59edd2aa2423a4f29e436 Mon Sep 17 00:00:00 2001 From: Bruno Bergher Date: Mon, 10 Nov 2025 13:06:56 +0000 Subject: [PATCH 3/7] More button tweaks --- webview-ui/src/components/chat/FollowUpSuggest.tsx | 7 ++----- webview-ui/src/components/ui/button.tsx | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/webview-ui/src/components/chat/FollowUpSuggest.tsx b/webview-ui/src/components/chat/FollowUpSuggest.tsx index d18ccc25173..8709089a1b8 100644 --- a/webview-ui/src/components/chat/FollowUpSuggest.tsx +++ b/webview-ui/src/components/chat/FollowUpSuggest.tsx @@ -108,11 +108,8 @@ export const FollowUpSuggest = ({ const isFirstSuggestion = index === 0 return ( -
+
+ ) })} @@ -254,44 +251,32 @@ export const AutoApproveDropdown = ({ disabled = false, triggerClassName = "" }: {/* Bottom bar with Select All/None buttons */}
- - +