Skip to content

Commit 3318366

Browse files
fix: standardize tooltip delays to 300ms (#5090) (#5098)
Co-authored-by: Daniel Riccio <[email protected]>
1 parent c797c9a commit 3318366

File tree

85 files changed

+1240
-796
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1240
-796
lines changed

webview-ui/src/App.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import ModesView from "./components/modes/ModesView"
2020
import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog"
2121
import { AccountView } from "./components/account/AccountView"
2222
import { useAddNonInteractiveClickListener } from "./components/ui/hooks/useNonInteractiveClick"
23+
import { TooltipProvider } from "./components/ui/tooltip"
24+
import { STANDARD_TOOLTIP_DELAY } from "./components/ui/standard-tooltip"
2325

2426
type Tab = "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account"
2527

@@ -215,7 +217,9 @@ const AppWithProviders = () => (
215217
<ExtensionStateContextProvider>
216218
<TranslationProvider>
217219
<QueryClientProvider client={queryClient}>
218-
<App />
220+
<TooltipProvider delayDuration={STANDARD_TOOLTIP_DELAY}>
221+
<App />
222+
</TooltipProvider>
219223
</QueryClientProvider>
220224
</TranslationProvider>
221225
</ExtensionStateContextProvider>

webview-ui/src/__tests__/App.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// npx vitest run src/__tests__/App.spec.tsx
22

33
import React from "react"
4-
import { render, screen, act, cleanup } from "@testing-library/react"
4+
import { render, screen, act, cleanup } from "@/utils/test-utils"
55

66
import AppWithProviders from "../App"
77

webview-ui/src/__tests__/ContextWindowProgress.spec.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// npm run test ContextWindowProgress.spec.tsx
22

3-
import { render, screen } from "@testing-library/react"
3+
import { render, screen } from "@/utils/test-utils"
44
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
55

66
import TaskHeader from "@src/components/chat/TaskHeader"
@@ -102,18 +102,22 @@ describe("ContextWindowProgress", () => {
102102
it("calculates percentages correctly", () => {
103103
renderComponent({ contextTokens: 1000, contextWindow: 4000 })
104104

105-
// Instead of checking the title attribute, verify the data-test-id
106-
// which identifies the element containing info about the percentage of tokens used
107-
const tokenUsageDiv = screen.getByTestId("context-tokens-used")
108-
expect(tokenUsageDiv).toBeInTheDocument()
105+
// Verify that the token count and window size are displayed correctly
106+
const tokenCount = screen.getByTestId("context-tokens-count")
107+
const windowSize = screen.getByTestId("context-window-size")
109108

110-
// Just verify that the element has a title attribute (the actual text is translated and may vary)
111-
expect(tokenUsageDiv).toHaveAttribute("title")
109+
expect(tokenCount).toBeInTheDocument()
110+
expect(tokenCount).toHaveTextContent("1000")
112111

113-
// We can't reliably test computed styles in JSDOM, so we'll just check
114-
// that the component appears to be working correctly by checking for expected elements
115-
// The context-window-label is not part of the ContextWindowProgress component
116-
expect(screen.getByTestId("context-tokens-count")).toBeInTheDocument()
117-
expect(screen.getByTestId("context-tokens-count")).toHaveTextContent("1000")
112+
expect(windowSize).toBeInTheDocument()
113+
expect(windowSize).toHaveTextContent("4000")
114+
115+
// The progress bar is now wrapped in tooltips, but we can verify the structure exists
116+
// by checking for the progress bar container
117+
const progressBarContainer = screen.getByTestId("context-tokens-count").parentElement
118+
expect(progressBarContainer).toBeInTheDocument()
119+
120+
// Verify the flex container has the expected structure
121+
expect(progressBarContainer?.querySelector(".flex-1.relative")).toBeInTheDocument()
118122
})
119123
})

webview-ui/src/components/account/__tests__/AccountView.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render, screen } from "@testing-library/react"
1+
import { render, screen } from "@/utils/test-utils"
22
import { describe, it, expect, vi } from "vitest"
33
import { AccountView } from "../AccountView"
44

webview-ui/src/components/chat/ChatTextArea.tsx

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
SearchResult,
2020
} from "@src/utils/context-mentions"
2121
import { convertToMentionPath } from "@/utils/path-mentions"
22-
import { SelectDropdown, DropdownOptionType, Button } from "@/components/ui"
22+
import { SelectDropdown, DropdownOptionType, Button, StandardTooltip } from "@/components/ui"
2323

2424
import Thumbnails from "../common/Thumbnails"
2525
import ModeSelector from "./ModeSelector"
@@ -1094,8 +1094,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
10941094
<div
10951095
className={cn("truncate min-w-0 overflow-hidden", {
10961096
"font-medium": isCurrentConfig,
1097-
})}
1098-
title={label}>
1097+
})}>
10991098
{label}
11001099
</div>
11011100
<div className="flex justify-end w-10 flex-shrink-0">
@@ -1106,21 +1105,25 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
11061105
})}>
11071106
<Check className="size-3" />
11081107
</div>
1109-
<Button
1110-
variant="ghost"
1111-
size="icon"
1112-
title={pinned ? t("chat:unpin") : t("chat:pin")}
1113-
onClick={(e) => {
1114-
e.stopPropagation()
1115-
togglePinnedApiConfig(value)
1116-
vscode.postMessage({ type: "toggleApiConfigPin", text: value })
1117-
}}
1118-
className={cn("size-5", {
1119-
"hidden group-hover:flex": !pinned,
1120-
"bg-accent": pinned,
1121-
})}>
1122-
<Pin className="size-3 p-0.5 opacity-50" />
1123-
</Button>
1108+
<StandardTooltip content={pinned ? t("chat:unpin") : t("chat:pin")}>
1109+
<Button
1110+
variant="ghost"
1111+
size="icon"
1112+
onClick={(e) => {
1113+
e.stopPropagation()
1114+
togglePinnedApiConfig(value)
1115+
vscode.postMessage({
1116+
type: "toggleApiConfigPin",
1117+
text: value,
1118+
})
1119+
}}
1120+
className={cn("size-5", {
1121+
"hidden group-hover:flex": !pinned,
1122+
"bg-accent": pinned,
1123+
})}>
1124+
<Pin className="size-3 p-0.5 opacity-50" />
1125+
</Button>
1126+
</StandardTooltip>
11241127
</div>
11251128
</div>
11261129
)

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { useExtensionState } from "@src/context/ExtensionStateContext"
3030
import { useSelectedModel } from "@src/components/ui/hooks/useSelectedModel"
3131
import RooHero from "@src/components/welcome/RooHero"
3232
import RooTips from "@src/components/welcome/RooTips"
33+
import { StandardTooltip } from "@src/components/ui"
3334

3435
import TelemetryBanner from "../common/TelemetryBanner"
3536
import { useTaskSearch } from "../history/useTaskSearch"
@@ -730,7 +731,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
730731
}
731732
},
732733
50,
733-
[isHidden, sendingDisabled, enableButtons]
734+
[isHidden, sendingDisabled, enableButtons],
734735
)
735736

736737
const visibleMessages = useMemo(() => {
@@ -1095,8 +1096,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
10951096

10961097
useEffect(() => {
10971098
return () => {
1098-
if (scrollToBottomSmooth && typeof (scrollToBottomSmooth as any).cancel === 'function') {
1099-
(scrollToBottomSmooth as any).cancel()
1099+
if (scrollToBottomSmooth && typeof (scrollToBottomSmooth as any).cancel === "function") {
1100+
;(scrollToBottomSmooth as any).cancel()
11001101
}
11011102
}
11021103
}, [scrollToBottomSmooth])
@@ -1476,15 +1477,16 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
14761477
<AutoApproveMenu />
14771478
{showScrollToBottom ? (
14781479
<div className="flex px-[15px] pt-[10px]">
1479-
<div
1480-
className="bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_55%,_transparent)] rounded-[3px] overflow-hidden cursor-pointer flex justify-center items-center flex-1 h-[25px] hover:bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_90%,_transparent)] active:bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_70%,_transparent)]"
1481-
onClick={() => {
1482-
scrollToBottomSmooth()
1483-
disableAutoScrollRef.current = false
1484-
}}
1485-
title={t("chat:scrollToBottom")}>
1486-
<span className="codicon codicon-chevron-down text-[18px]"></span>
1487-
</div>
1480+
<StandardTooltip content={t("chat:scrollToBottom")}>
1481+
<div
1482+
className="bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_55%,_transparent)] rounded-[3px] overflow-hidden cursor-pointer flex justify-center items-center flex-1 h-[25px] hover:bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_90%,_transparent)] active:bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_70%,_transparent)]"
1483+
onClick={() => {
1484+
scrollToBottomSmooth()
1485+
disableAutoScrollRef.current = false
1486+
}}>
1487+
<span className="codicon codicon-chevron-down text-[18px]"></span>
1488+
</div>
1489+
</StandardTooltip>
14881490
</div>
14891491
) : (
14901492
<div
@@ -1498,11 +1500,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
14981500
: "opacity-0"
14991501
}`}>
15001502
{primaryButtonText && !isStreaming && (
1501-
<VSCodeButton
1502-
appearance="primary"
1503-
disabled={!enableButtons}
1504-
className={secondaryButtonText ? "flex-1 mr-[6px]" : "flex-[2] mr-0"}
1505-
title={
1503+
<StandardTooltip
1504+
content={
15061505
primaryButtonText === t("chat:retry.title")
15071506
? t("chat:retry.tooltip")
15081507
: primaryButtonText === t("chat:save.title")
@@ -1521,17 +1520,19 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
15211520
t("chat:proceedWhileRunning.title")
15221521
? t("chat:proceedWhileRunning.tooltip")
15231522
: undefined
1524-
}
1525-
onClick={() => handlePrimaryButtonClick(inputValue, selectedImages)}>
1526-
{primaryButtonText}
1527-
</VSCodeButton>
1523+
}>
1524+
<VSCodeButton
1525+
appearance="primary"
1526+
disabled={!enableButtons}
1527+
className={secondaryButtonText ? "flex-1 mr-[6px]" : "flex-[2] mr-0"}
1528+
onClick={() => handlePrimaryButtonClick(inputValue, selectedImages)}>
1529+
{primaryButtonText}
1530+
</VSCodeButton>
1531+
</StandardTooltip>
15281532
)}
15291533
{(secondaryButtonText || isStreaming) && (
1530-
<VSCodeButton
1531-
appearance="secondary"
1532-
disabled={!enableButtons && !(isStreaming && !didClickCancel)}
1533-
className={isStreaming ? "flex-[2] ml-0" : "flex-1 ml-[6px]"}
1534-
title={
1534+
<StandardTooltip
1535+
content={
15351536
isStreaming
15361537
? t("chat:cancel.tooltip")
15371538
: secondaryButtonText === t("chat:startNewTask.title")
@@ -1541,10 +1542,15 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
15411542
: secondaryButtonText === t("chat:terminate.title")
15421543
? t("chat:terminate.tooltip")
15431544
: undefined
1544-
}
1545-
onClick={() => handleSecondaryButtonClick(inputValue, selectedImages)}>
1546-
{isStreaming ? t("chat:cancel.title") : secondaryButtonText}
1547-
</VSCodeButton>
1545+
}>
1546+
<VSCodeButton
1547+
appearance="secondary"
1548+
disabled={!enableButtons && !(isStreaming && !didClickCancel)}
1549+
className={isStreaming ? "flex-[2] ml-0" : "flex-1 ml-[6px]"}
1550+
onClick={() => handleSecondaryButtonClick(inputValue, selectedImages)}>
1551+
{isStreaming ? t("chat:cancel.title") : secondaryButtonText}
1552+
</VSCodeButton>
1553+
</StandardTooltip>
15481554
)}
15491555
</div>
15501556
)}

webview-ui/src/components/chat/CodebaseSearchResult.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from "react"
22
import { vscode } from "@src/utils/vscode"
3+
import { StandardTooltip } from "@/components/ui"
34

45
interface CodebaseSearchResultProps {
56
filePath: string
@@ -23,19 +24,20 @@ const CodebaseSearchResult: React.FC<CodebaseSearchResultProps> = ({ filePath, s
2324
}
2425

2526
return (
26-
<div
27-
onClick={handleClick}
28-
className="mb-1 p-2 border border-primary rounded cursor-pointer hover:bg-secondary hover:text-white"
29-
title={`Score: ${score.toFixed(2)}`}>
30-
<div className="flex gap-2 items-center overflow-hidden">
31-
<span className="text-primary-300 whitespace-nowrap flex-shrink-0">
32-
{filePath.split("/").at(-1)}:{startLine}-{endLine}
33-
</span>
34-
<span className="text-gray-500 truncate min-w-0 flex-1">
35-
{filePath.split("/").slice(0, -1).join("/")}
36-
</span>
27+
<StandardTooltip content={`Score: ${score.toFixed(2)}`}>
28+
<div
29+
onClick={handleClick}
30+
className="mb-1 p-2 border border-primary rounded cursor-pointer hover:bg-secondary hover:text-white">
31+
<div className="flex gap-2 items-center overflow-hidden">
32+
<span className="text-primary-300 whitespace-nowrap flex-shrink-0">
33+
{filePath.split("/").at(-1)}:{startLine}-{endLine}
34+
</span>
35+
<span className="text-gray-500 truncate min-w-0 flex-1">
36+
{filePath.split("/").slice(0, -1).join("/")}
37+
</span>
38+
</div>
3739
</div>
38-
</div>
40+
</StandardTooltip>
3941
)
4042
}
4143

0 commit comments

Comments
 (0)