Просмотр исходного кода

Add tooltips on checkpoint actions

Roo Code 10 месяцев назад
Родитель
Сommit
0daab656f1

+ 246 - 0
webview-ui/package-lock.json

@@ -13,6 +13,7 @@
 				"@radix-ui/react-icons": "^1.3.2",
 				"@radix-ui/react-popover": "^1.1.6",
 				"@radix-ui/react-slot": "^1.1.1",
+				"@radix-ui/react-tooltip": "^1.1.8",
 				"@tailwindcss/vite": "^4.0.0",
 				"@vscode/webview-ui-toolkit": "^1.4.0",
 				"class-variance-authority": "^0.7.1",
@@ -4185,6 +4186,187 @@
 				}
 			}
 		},
+		"node_modules/@radix-ui/react-tooltip": {
+			"version": "1.1.8",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz",
+			"integrity": "sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/primitive": "1.1.1",
+				"@radix-ui/react-compose-refs": "1.1.1",
+				"@radix-ui/react-context": "1.1.1",
+				"@radix-ui/react-dismissable-layer": "1.1.5",
+				"@radix-ui/react-id": "1.1.0",
+				"@radix-ui/react-popper": "1.2.2",
+				"@radix-ui/react-portal": "1.1.4",
+				"@radix-ui/react-presence": "1.1.2",
+				"@radix-ui/react-primitive": "2.0.2",
+				"@radix-ui/react-slot": "1.1.2",
+				"@radix-ui/react-use-controllable-state": "1.1.0",
+				"@radix-ui/react-visually-hidden": "1.1.2"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
+			"integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-primitive": "2.0.2"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": {
+			"version": "1.1.5",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
+			"integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/primitive": "1.1.1",
+				"@radix-ui/react-compose-refs": "1.1.1",
+				"@radix-ui/react-primitive": "2.0.2",
+				"@radix-ui/react-use-callback-ref": "1.1.0",
+				"@radix-ui/react-use-escape-keydown": "1.1.0"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": {
+			"version": "1.2.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
+			"integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
+			"license": "MIT",
+			"dependencies": {
+				"@floating-ui/react-dom": "^2.0.0",
+				"@radix-ui/react-arrow": "1.1.2",
+				"@radix-ui/react-compose-refs": "1.1.1",
+				"@radix-ui/react-context": "1.1.1",
+				"@radix-ui/react-primitive": "2.0.2",
+				"@radix-ui/react-use-callback-ref": "1.1.0",
+				"@radix-ui/react-use-layout-effect": "1.1.0",
+				"@radix-ui/react-use-rect": "1.1.0",
+				"@radix-ui/react-use-size": "1.1.0",
+				"@radix-ui/rect": "1.1.0"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": {
+			"version": "1.1.4",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
+			"integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-primitive": "2.0.2",
+				"@radix-ui/react-use-layout-effect": "1.1.0"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+			"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-slot": "1.1.2"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+			"integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-compose-refs": "1.1.1"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
 		"node_modules/@radix-ui/react-use-callback-ref": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
@@ -4287,6 +4469,70 @@
 				}
 			}
 		},
+		"node_modules/@radix-ui/react-visually-hidden": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz",
+			"integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-primitive": "2.0.2"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
+			"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-slot": "1.1.2"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
+			"integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-compose-refs": "1.1.1"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
 		"node_modules/@radix-ui/rect": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",

+ 1 - 0
webview-ui/package.json

@@ -20,6 +20,7 @@
 		"@radix-ui/react-icons": "^1.3.2",
 		"@radix-ui/react-popover": "^1.1.6",
 		"@radix-ui/react-slot": "^1.1.1",
+		"@radix-ui/react-tooltip": "^1.1.8",
 		"@tailwindcss/vite": "^4.0.0",
 		"@vscode/webview-ui-toolkit": "^1.4.0",
 		"class-variance-authority": "^0.7.1",

+ 30 - 7
webview-ui/src/components/chat/checkpoints/CheckpointMenu.tsx

@@ -3,7 +3,16 @@ import { CheckIcon, Cross2Icon } from "@radix-ui/react-icons"
 
 import { vscode } from "../../../utils/vscode"
 
-import { Button, Popover, PopoverContent, PopoverTrigger } from "@/components/ui"
+import {
+	Button,
+	Popover,
+	PopoverContent,
+	PopoverTrigger,
+	Tooltip,
+	TooltipContent,
+	TooltipProvider,
+	TooltipTrigger,
+} from "@/components/ui"
 
 type CheckpointMenuProps = {
 	ts: number
@@ -43,9 +52,16 @@ export const CheckpointMenu = ({ ts, commitHash, currentCheckpointHash }: Checkp
 
 	return (
 		<div className="flex flex-row gap-1">
-			<Button variant="ghost" size="icon" onClick={onCheckpointDiff}>
-				<span className="codicon codicon-diff-single" />
-			</Button>
+			<TooltipProvider>
+				<Tooltip>
+					<TooltipTrigger asChild>
+						<Button variant="ghost" size="icon" onClick={onCheckpointDiff}>
+							<span className="codicon codicon-diff-single" />
+						</Button>
+					</TooltipTrigger>
+					<TooltipContent align="end">View Diff</TooltipContent>
+				</Tooltip>
+			</TooltipProvider>
 			<Popover
 				open={isOpen}
 				onOpenChange={(open) => {
@@ -53,9 +69,16 @@ export const CheckpointMenu = ({ ts, commitHash, currentCheckpointHash }: Checkp
 					setIsConfirming(false)
 				}}>
 				<PopoverTrigger asChild>
-					<Button variant="ghost" size="icon">
-						<span className="codicon codicon-history" />
-					</Button>
+					<TooltipProvider>
+						<Tooltip>
+							<TooltipTrigger asChild>
+								<Button variant="ghost" size="icon">
+									<span className="codicon codicon-history" />
+								</Button>
+							</TooltipTrigger>
+							<TooltipContent align="end">Restore Checkpoint</TooltipContent>
+						</Tooltip>
+					</TooltipProvider>
 				</PopoverTrigger>
 				<PopoverContent align="end" container={portalContainer}>
 					<div className="flex flex-col gap-2">

+ 1 - 0
webview-ui/src/components/ui/index.ts

@@ -3,3 +3,4 @@ export * from "./command"
 export * from "./dialog"
 export * from "./dropdown-menu"
 export * from "./popover"
+export * from "./tooltip"

+ 30 - 0
webview-ui/src/components/ui/tooltip.tsx

@@ -0,0 +1,30 @@
+import * as React from "react"
+import * as TooltipPrimitive from "@radix-ui/react-tooltip"
+
+import { cn } from "@/lib/utils"
+
+const TooltipProvider = TooltipPrimitive.Provider
+
+const Tooltip = TooltipPrimitive.Root
+
+const TooltipTrigger = TooltipPrimitive.Trigger
+
+const TooltipContent = React.forwardRef<
+	React.ElementRef<typeof TooltipPrimitive.Content>,
+	React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
+>(({ className, sideOffset = 4, ...props }, ref) => (
+	<TooltipPrimitive.Portal>
+		<TooltipPrimitive.Content
+			ref={ref}
+			sideOffset={sideOffset}
+			className={cn(
+				"z-50 overflow-hidden rounded-xs bg-vscode-notifications-background border border-vscode-notifications-border px-3 py-1.5 text-xs text-vscode-notifications-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
+				className,
+			)}
+			{...props}
+		/>
+	</TooltipPrimitive.Portal>
+))
+TooltipContent.displayName = TooltipPrimitive.Content.displayName
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }

+ 7 - 0
webview-ui/src/index.css

@@ -76,6 +76,13 @@
 
 	--color-vscode-input-background: var(--vscode-input-background);
 	--color-vscode-input-border: var(--vscode-input-border);
+
+	--color-vscode-badge-foreground: var(--vscode-badge-foreground);
+	--color-vscode-badge-background: var(--vscode-badge-background);
+
+	--color-vscode-notifications-foreground: var(--vscode-notifications-foreground);
+	--color-vscode-notifications-background: var(--vscode-notifications-background);
+	--color-vscode-notifications-border: var(--vscode-notifications-border);
 }
 
 @layer base {