mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
Visual tweaks
This commit is contained in:
parent
31fd2b9b15
commit
1fd6199f2a
5 changed files with 95 additions and 136 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { memo, useCallback, useMemo, useState } from "react"
|
||||
import { Trans } from "react-i18next"
|
||||
import { VSCodeCheckbox, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { Stamp, ListChecks, LayoutList } from "lucide-react"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
|
@ -23,8 +23,6 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
const portalContainer = useRooPortal("roo-portal")
|
||||
|
||||
const {
|
||||
autoApprovalEnabled,
|
||||
setAutoApprovalEnabled,
|
||||
alwaysApproveResubmit,
|
||||
setAlwaysAllowReadOnly,
|
||||
setAlwaysAllowWrite,
|
||||
|
|
@ -51,7 +49,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
[baseToggles, alwaysApproveResubmit],
|
||||
)
|
||||
|
||||
const { hasEnabledOptions, effectiveAutoApprovalEnabled } = useAutoApprovalState(toggles, autoApprovalEnabled)
|
||||
const { hasEnabledOptions, effectiveAutoApprovalEnabled } = useAutoApprovalState(toggles, true)
|
||||
|
||||
const onAutoApproveToggle = useCallback(
|
||||
(key: AutoApproveSetting, value: boolean) => {
|
||||
|
|
@ -90,30 +88,9 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
setAlwaysAllowUpdateTodoList(value)
|
||||
break
|
||||
}
|
||||
|
||||
// Check if we need to update the master auto-approval state
|
||||
// Create a new toggles state with the updated value
|
||||
const updatedToggles = {
|
||||
...toggles,
|
||||
[key]: value,
|
||||
}
|
||||
|
||||
const willHaveEnabledOptions = Object.values(updatedToggles).some((v) => !!v)
|
||||
|
||||
// If enabling the first option, enable master auto-approval
|
||||
if (value && !hasEnabledOptions && willHaveEnabledOptions) {
|
||||
setAutoApprovalEnabled(true)
|
||||
vscode.postMessage({ type: "autoApprovalEnabled", bool: true })
|
||||
}
|
||||
// If disabling the last option, disable master auto-approval
|
||||
else if (!value && hasEnabledOptions && !willHaveEnabledOptions) {
|
||||
setAutoApprovalEnabled(false)
|
||||
vscode.postMessage({ type: "autoApprovalEnabled", bool: false })
|
||||
}
|
||||
},
|
||||
[
|
||||
toggles,
|
||||
hasEnabledOptions,
|
||||
setAlwaysAllowReadOnly,
|
||||
setAlwaysAllowWrite,
|
||||
setAlwaysAllowExecute,
|
||||
|
|
@ -124,7 +101,6 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
setAlwaysApproveResubmit,
|
||||
setAlwaysAllowFollowupQuestions,
|
||||
setAlwaysAllowUpdateTodoList,
|
||||
setAutoApprovalEnabled,
|
||||
],
|
||||
)
|
||||
|
||||
|
|
@ -170,14 +146,14 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
const trigger = (
|
||||
<PopoverTrigger
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1.5 relative whitespace-nowrap px-2 py-1 text-xs",
|
||||
"inline-flex items-center gap-1.5 relative whitespace-nowrap px-2 py-1 text-xs flex-shrink-1",
|
||||
"bg-transparent border border-[rgba(255,255,255,0.08)] rounded-md text-vscode-foreground",
|
||||
"transition-all duration-150 focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder focus-visible:ring-inset",
|
||||
"opacity-90 hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)] cursor-pointer",
|
||||
)}
|
||||
style={style}>
|
||||
<Stamp className="size-3.5 opacity-80 flex-shrink-0" />
|
||||
<span className="font-medium">{t("chat:autoApprove.title")}</span>
|
||||
<span className="font-medium">{t("chat:autoApprove.dropdownTitle")}</span>
|
||||
<span className="text-vscode-descriptionForeground truncate max-w-[200px]">{displayText}</span>
|
||||
</PopoverTrigger>
|
||||
)
|
||||
|
|
@ -192,50 +168,11 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
container={portalContainer}
|
||||
className="p-0 overflow-hidden min-w-[400px] max-w-[500px]">
|
||||
<div className="flex flex-col w-full">
|
||||
{/* Header with master toggle */}
|
||||
<div className="flex items-center justify-between p-3 border-b border-vscode-dropdown-border">
|
||||
<div className="flex items-center gap-2">
|
||||
<StandardTooltip
|
||||
content={!hasEnabledOptions ? t("chat:autoApprove.selectOptionsFirst") : undefined}>
|
||||
<VSCodeCheckbox
|
||||
checked={effectiveAutoApprovalEnabled}
|
||||
disabled={!hasEnabledOptions}
|
||||
aria-label={
|
||||
hasEnabledOptions
|
||||
? t("chat:autoApprove.toggleAriaLabel")
|
||||
: t("chat:autoApprove.disabledAriaLabel")
|
||||
}
|
||||
onChange={() => {
|
||||
if (hasEnabledOptions) {
|
||||
const newValue = !(autoApprovalEnabled ?? false)
|
||||
setAutoApprovalEnabled(newValue)
|
||||
vscode.postMessage({ type: "autoApprovalEnabled", bool: newValue })
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</StandardTooltip>
|
||||
<h4 className="m-0 font-medium text-sm">{t("chat:autoApprove.title")}</h4>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<StandardTooltip content={t("chat:autoApprove.selectAll")}>
|
||||
<button
|
||||
onClick={handleSelectAll}
|
||||
className="p-1 rounded hover:bg-vscode-list-hoverBackground transition-colors">
|
||||
<ListChecks className="size-4" />
|
||||
</button>
|
||||
</StandardTooltip>
|
||||
<StandardTooltip content={t("chat:autoApprove.selectNone")}>
|
||||
<button
|
||||
onClick={handleSelectNone}
|
||||
className="p-1 rounded hover:bg-vscode-list-hoverBackground transition-colors">
|
||||
<LayoutList className="size-4" />
|
||||
</button>
|
||||
</StandardTooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="px-3 py-2 border-b border-vscode-dropdown-border">
|
||||
{/* Header */}
|
||||
<div className="p-3 border-b border-vscode-dropdown-border">
|
||||
<h3 className="m-0 font-bold text-sm text-vscode-button-foreground pb-2">
|
||||
{t("chat:autoApprove.title")}
|
||||
</h3>
|
||||
<div
|
||||
style={{
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
|
|
@ -256,6 +193,24 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
<AutoApproveToggleDropdown {...toggles} onToggle={onAutoApproveToggle} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer with buttons on left and title on right */}
|
||||
<div className="flex items-center justify-between px-3 py-2 border-t border-vscode-dropdown-border">
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={handleSelectAll}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1 text-xs rounded border border-vscode-button-border bg-vscode-button-secondaryBackground text-vscode-button-secondaryForeground hover:bg-vscode-button-secondaryHoverBackground transition-colors cursor-pointer">
|
||||
<ListChecks className="size-3.5" />
|
||||
All
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSelectNone}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1 text-xs rounded border border-vscode-button-border bg-vscode-button-secondaryBackground text-vscode-button-secondaryForeground hover:bg-vscode-button-secondaryHoverBackground transition-colors cursor-pointer">
|
||||
<LayoutList className="size-3.5" />
|
||||
None
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
|
|
|||
|
|
@ -56,20 +56,22 @@ export const AutoApproveToggleDropdown = ({ onToggle, ...props }: AutoApproveTog
|
|||
data-testid={testId}
|
||||
className={cn(
|
||||
"w-full flex items-center gap-2 px-2 py-1.5 rounded text-xs text-left",
|
||||
"transition-colors hover:bg-vscode-list-hoverBackground",
|
||||
"transition-colors hover:bg-vscode-list-hoverBackground cursor-pointer",
|
||||
props[key]
|
||||
? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground"
|
||||
: "opacity-70",
|
||||
)}>
|
||||
<span className={cn("codicon", `codicon-${icon}`, "text-sm flex-shrink-0")} />
|
||||
<span className="flex-1 truncate">{t(labelKey)}</span>
|
||||
<span
|
||||
className={cn(
|
||||
"text-[10px] px-1 rounded",
|
||||
props[key] ? "bg-vscode-badge-background text-vscode-badge-foreground" : "",
|
||||
)}>
|
||||
{props[key] ? "✓" : ""}
|
||||
</span>
|
||||
{DEFAULT_KEYBOARD_CONFIG.enabled && (
|
||||
<span
|
||||
className={cn(
|
||||
"text-[10px] px-1 rounded",
|
||||
"bg-vscode-badge-background text-vscode-badge-foreground opacity-60",
|
||||
)}>
|
||||
{shortcutDisplay.replace("Alt+", "⌥").replace("Ctrl+Shift+", "⌃⇧")}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</StandardTooltip>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import { SlashCommandsPopover } from "./SlashCommandsPopover"
|
|||
import { cn } from "@/lib/utils"
|
||||
import { usePromptHistory } from "./hooks/usePromptHistory"
|
||||
import { EditModeControls } from "./EditModeControls"
|
||||
import AutoApproveMenu from "./AutoApproveMenu"
|
||||
|
||||
interface ChatTextAreaProps {
|
||||
inputValue: string
|
||||
|
|
@ -917,31 +918,58 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|||
|
||||
// Helper function to render non-edit mode controls
|
||||
const renderNonEditModeControls = () => (
|
||||
<div className={cn("flex", "justify-between", "items-center", "mt-auto")}>
|
||||
<div className={cn("flex", "items-center", "gap-1", "min-w-0")}>
|
||||
<div className="shrink-0">{renderModeSelector()}</div>
|
||||
<div className={cn("flex", "flex-col", "gap-1", "mt-auto")}>
|
||||
<div className={cn("flex", "justify-between", "items-center")}>
|
||||
<div className={cn("flex", "items-center", "gap-1", "min-w-0", "flex-nowrap")}>
|
||||
<div>{renderModeSelector()}</div>
|
||||
|
||||
<div className={cn("flex-1", "min-w-0", "overflow-hidden")}>
|
||||
<ApiConfigSelector
|
||||
value={currentConfigId}
|
||||
displayName={displayName}
|
||||
disabled={selectApiConfigDisabled}
|
||||
title={t("chat:selectApiConfig")}
|
||||
onChange={handleApiConfigChange}
|
||||
triggerClassName="w-full text-ellipsis overflow-hidden"
|
||||
listApiConfigMeta={listApiConfigMeta || []}
|
||||
pinnedApiConfigs={pinnedApiConfigs}
|
||||
togglePinnedApiConfig={togglePinnedApiConfig}
|
||||
/>
|
||||
<div>
|
||||
<ApiConfigSelector
|
||||
value={currentConfigId}
|
||||
displayName={displayName}
|
||||
disabled={selectApiConfigDisabled}
|
||||
title={t("chat:selectApiConfig")}
|
||||
onChange={handleApiConfigChange}
|
||||
triggerClassName="w-full text-ellipsis overflow-hidden"
|
||||
listApiConfigMeta={listApiConfigMeta || []}
|
||||
pinnedApiConfigs={pinnedApiConfigs}
|
||||
togglePinnedApiConfig={togglePinnedApiConfig}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grow-1 shrink max-w-100% overflow-hidden">
|
||||
<AutoApproveMenu />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={cn("flex", "items-center", "gap-0.5", "shrink-0")}>
|
||||
{isTtsPlaying && (
|
||||
<StandardTooltip content={t("chat:stopTts")}>
|
||||
<div className={cn("flex", "items-center", "gap-0.5", "shrink-0")}>
|
||||
{isTtsPlaying && (
|
||||
<StandardTooltip content={t("chat:stopTts")}>
|
||||
<button
|
||||
aria-label={t("chat:stopTts")}
|
||||
onClick={() => vscode.postMessage({ type: "stopTts" })}
|
||||
className={cn(
|
||||
"relative inline-flex items-center justify-center",
|
||||
"bg-transparent border-none p-1.5",
|
||||
"rounded-md min-w-[28px] min-h-[28px]",
|
||||
"text-vscode-foreground opacity-85",
|
||||
"transition-all duration-150",
|
||||
"hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
|
||||
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
|
||||
"active:bg-[rgba(255,255,255,0.1)]",
|
||||
"cursor-pointer",
|
||||
)}>
|
||||
<VolumeX className="w-4 h-4" />
|
||||
</button>
|
||||
</StandardTooltip>
|
||||
)}
|
||||
<SlashCommandsPopover />
|
||||
<IndexingStatusBadge />
|
||||
<StandardTooltip content={t("chat:addImages")}>
|
||||
<button
|
||||
aria-label={t("chat:stopTts")}
|
||||
onClick={() => vscode.postMessage({ type: "stopTts" })}
|
||||
aria-label={t("chat:addImages")}
|
||||
disabled={shouldDisableImages}
|
||||
onClick={!shouldDisableImages ? onSelectImages : undefined}
|
||||
className={cn(
|
||||
"relative inline-flex items-center justify-center",
|
||||
"bg-transparent border-none p-1.5",
|
||||
|
|
@ -951,36 +979,15 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|||
"hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
|
||||
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
|
||||
"active:bg-[rgba(255,255,255,0.1)]",
|
||||
"cursor-pointer",
|
||||
!shouldDisableImages && "cursor-pointer",
|
||||
shouldDisableImages &&
|
||||
"opacity-40 cursor-not-allowed grayscale-[30%] hover:bg-transparent hover:border-[rgba(255,255,255,0.08)] active:bg-transparent",
|
||||
"mr-1",
|
||||
)}>
|
||||
<VolumeX className="w-4 h-4" />
|
||||
<Image className="w-4 h-4" />
|
||||
</button>
|
||||
</StandardTooltip>
|
||||
)}
|
||||
<SlashCommandsPopover />
|
||||
<IndexingStatusBadge />
|
||||
<StandardTooltip content={t("chat:addImages")}>
|
||||
<button
|
||||
aria-label={t("chat:addImages")}
|
||||
disabled={shouldDisableImages}
|
||||
onClick={!shouldDisableImages ? onSelectImages : undefined}
|
||||
className={cn(
|
||||
"relative inline-flex items-center justify-center",
|
||||
"bg-transparent border-none p-1.5",
|
||||
"rounded-md min-w-[28px] min-h-[28px]",
|
||||
"text-vscode-foreground opacity-85",
|
||||
"transition-all duration-150",
|
||||
"hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
|
||||
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
|
||||
"active:bg-[rgba(255,255,255,0.1)]",
|
||||
!shouldDisableImages && "cursor-pointer",
|
||||
shouldDisableImages &&
|
||||
"opacity-40 cursor-not-allowed grayscale-[30%] hover:bg-transparent hover:border-[rgba(255,255,255,0.08)] active:bg-transparent",
|
||||
"mr-1",
|
||||
)}>
|
||||
<Image className="w-4 h-4" />
|
||||
</button>
|
||||
</StandardTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ import BrowserSessionRow from "./BrowserSessionRow"
|
|||
import ChatRow from "./ChatRow"
|
||||
import ChatTextArea from "./ChatTextArea"
|
||||
import TaskHeader from "./TaskHeader"
|
||||
import AutoApproveMenu from "./AutoApproveMenu"
|
||||
import { AutoApproveKeyboardShortcuts } from "./AutoApproveKeyboardShortcuts"
|
||||
import SystemPromptWarning from "./SystemPromptWarning"
|
||||
import ProfileViolationWarning from "./ProfileViolationWarning"
|
||||
|
|
@ -2019,11 +2018,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
modeShortcutText={modeShortcutText}
|
||||
/>
|
||||
|
||||
{/* Auto-Approve Menu positioned below text area */}
|
||||
<div className="px-3 pb-2">
|
||||
<AutoApproveMenu />
|
||||
</div>
|
||||
|
||||
{isProfileDisabled && (
|
||||
<div className="px-3">
|
||||
<ProfileViolationWarning />
|
||||
|
|
|
|||
|
|
@ -265,9 +265,10 @@
|
|||
"issues": "It seems like you're having Windows PowerShell issues, please see this"
|
||||
},
|
||||
"autoApprove": {
|
||||
"title": "Auto-approve:",
|
||||
"title": "Auto-Approve",
|
||||
"dropdownTitle": "Auto:",
|
||||
"none": "None",
|
||||
"description": "Auto-approve allows Roo Code to perform actions without asking for permission. Only enable for actions you fully trust. More detailed configuration available in <settingsLink>Settings</settingsLink>.",
|
||||
"description": "Run these actions without asking for permission.Only enable for actions you fully trust. More in <settingsLink>Settings</settingsLink>.",
|
||||
"selectOptionsFirst": "Select at least one option below to enable auto-approval",
|
||||
"toggleAriaLabel": "Toggle auto-approval",
|
||||
"disabledAriaLabel": "Auto-approval disabled - select options first"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue