|
@@ -1,31 +1,11 @@
|
|
|
-import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
|
|
|
|
-import { useCallback, useState } from "react"
|
|
|
|
|
|
|
+import { useCallback, useMemo, useState } from "react"
|
|
|
import { Trans } from "react-i18next"
|
|
import { Trans } from "react-i18next"
|
|
|
-import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
|
|
|
|
-
|
|
|
|
|
-import { Button } from "@/components/ui"
|
|
|
|
|
|
|
+import { VSCodeCheckbox, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
|
|
|
|
|
|
|
import { vscode } from "../../utils/vscode"
|
|
import { vscode } from "../../utils/vscode"
|
|
|
import { useExtensionState } from "../../context/ExtensionStateContext"
|
|
import { useExtensionState } from "../../context/ExtensionStateContext"
|
|
|
import { useAppTranslation } from "../../i18n/TranslationContext"
|
|
import { useAppTranslation } from "../../i18n/TranslationContext"
|
|
|
-
|
|
|
|
|
-const ICON_MAP: Record<string, string> = {
|
|
|
|
|
- readFiles: "eye",
|
|
|
|
|
- editFiles: "edit",
|
|
|
|
|
- executeCommands: "terminal",
|
|
|
|
|
- useBrowser: "globe",
|
|
|
|
|
- useMcp: "plug",
|
|
|
|
|
- switchModes: "sync",
|
|
|
|
|
- subtasks: "discard",
|
|
|
|
|
- retryRequests: "refresh",
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-interface AutoApproveAction {
|
|
|
|
|
- id: string
|
|
|
|
|
- label: string
|
|
|
|
|
- enabled: boolean
|
|
|
|
|
- description: string
|
|
|
|
|
-}
|
|
|
|
|
|
|
+import { AutoApproveToggle, AutoApproveSetting, autoApproveSettingsConfig } from "../settings/AutoApproveToggle"
|
|
|
|
|
|
|
|
interface AutoApproveMenuProps {
|
|
interface AutoApproveMenuProps {
|
|
|
style?: React.CSSProperties
|
|
style?: React.CSSProperties
|
|
@@ -33,157 +13,108 @@ interface AutoApproveMenuProps {
|
|
|
|
|
|
|
|
const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|
const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|
|
const [isExpanded, setIsExpanded] = useState(false)
|
|
const [isExpanded, setIsExpanded] = useState(false)
|
|
|
|
|
+
|
|
|
const {
|
|
const {
|
|
|
|
|
+ autoApprovalEnabled,
|
|
|
|
|
+ setAutoApprovalEnabled,
|
|
|
alwaysAllowReadOnly,
|
|
alwaysAllowReadOnly,
|
|
|
- setAlwaysAllowReadOnly,
|
|
|
|
|
alwaysAllowWrite,
|
|
alwaysAllowWrite,
|
|
|
- setAlwaysAllowWrite,
|
|
|
|
|
alwaysAllowExecute,
|
|
alwaysAllowExecute,
|
|
|
- setAlwaysAllowExecute,
|
|
|
|
|
alwaysAllowBrowser,
|
|
alwaysAllowBrowser,
|
|
|
- setAlwaysAllowBrowser,
|
|
|
|
|
alwaysAllowMcp,
|
|
alwaysAllowMcp,
|
|
|
- setAlwaysAllowMcp,
|
|
|
|
|
alwaysAllowModeSwitch,
|
|
alwaysAllowModeSwitch,
|
|
|
- setAlwaysAllowModeSwitch,
|
|
|
|
|
alwaysAllowSubtasks,
|
|
alwaysAllowSubtasks,
|
|
|
- setAlwaysAllowSubtasks,
|
|
|
|
|
alwaysApproveResubmit,
|
|
alwaysApproveResubmit,
|
|
|
|
|
+ setAlwaysAllowReadOnly,
|
|
|
|
|
+ setAlwaysAllowWrite,
|
|
|
|
|
+ setAlwaysAllowExecute,
|
|
|
|
|
+ setAlwaysAllowBrowser,
|
|
|
|
|
+ setAlwaysAllowMcp,
|
|
|
|
|
+ setAlwaysAllowModeSwitch,
|
|
|
|
|
+ setAlwaysAllowSubtasks,
|
|
|
setAlwaysApproveResubmit,
|
|
setAlwaysApproveResubmit,
|
|
|
- autoApprovalEnabled,
|
|
|
|
|
- setAutoApprovalEnabled,
|
|
|
|
|
} = useExtensionState()
|
|
} = useExtensionState()
|
|
|
|
|
|
|
|
const { t } = useAppTranslation()
|
|
const { t } = useAppTranslation()
|
|
|
|
|
|
|
|
- const actions: AutoApproveAction[] = [
|
|
|
|
|
- {
|
|
|
|
|
- id: "readFiles",
|
|
|
|
|
- label: t("chat:autoApprove.actions.readFiles.label"),
|
|
|
|
|
- enabled: alwaysAllowReadOnly ?? false,
|
|
|
|
|
- description: t("chat:autoApprove.actions.readFiles.description"),
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: "editFiles",
|
|
|
|
|
- label: t("chat:autoApprove.actions.editFiles.label"),
|
|
|
|
|
- enabled: alwaysAllowWrite ?? false,
|
|
|
|
|
- description: t("chat:autoApprove.actions.editFiles.description"),
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: "executeCommands",
|
|
|
|
|
- label: t("chat:autoApprove.actions.executeCommands.label"),
|
|
|
|
|
- enabled: alwaysAllowExecute ?? false,
|
|
|
|
|
- description: t("chat:autoApprove.actions.executeCommands.description"),
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: "useBrowser",
|
|
|
|
|
- label: t("chat:autoApprove.actions.useBrowser.label"),
|
|
|
|
|
- enabled: alwaysAllowBrowser ?? false,
|
|
|
|
|
- description: t("chat:autoApprove.actions.useBrowser.description"),
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: "useMcp",
|
|
|
|
|
- label: t("chat:autoApprove.actions.useMcp.label"),
|
|
|
|
|
- enabled: alwaysAllowMcp ?? false,
|
|
|
|
|
- description: t("chat:autoApprove.actions.useMcp.description"),
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: "switchModes",
|
|
|
|
|
- label: t("chat:autoApprove.actions.switchModes.label"),
|
|
|
|
|
- enabled: alwaysAllowModeSwitch ?? false,
|
|
|
|
|
- description: t("chat:autoApprove.actions.switchModes.description"),
|
|
|
|
|
|
|
+ const onAutoApproveToggle = useCallback(
|
|
|
|
|
+ (key: AutoApproveSetting, value: boolean) => {
|
|
|
|
|
+ vscode.postMessage({ type: key, bool: value })
|
|
|
|
|
+
|
|
|
|
|
+ switch (key) {
|
|
|
|
|
+ case "alwaysAllowReadOnly":
|
|
|
|
|
+ setAlwaysAllowReadOnly(value)
|
|
|
|
|
+ break
|
|
|
|
|
+ case "alwaysAllowWrite":
|
|
|
|
|
+ setAlwaysAllowWrite(value)
|
|
|
|
|
+ break
|
|
|
|
|
+ case "alwaysAllowExecute":
|
|
|
|
|
+ setAlwaysAllowExecute(value)
|
|
|
|
|
+ break
|
|
|
|
|
+ case "alwaysAllowBrowser":
|
|
|
|
|
+ setAlwaysAllowBrowser(value)
|
|
|
|
|
+ break
|
|
|
|
|
+ case "alwaysAllowMcp":
|
|
|
|
|
+ setAlwaysAllowMcp(value)
|
|
|
|
|
+ break
|
|
|
|
|
+ case "alwaysAllowModeSwitch":
|
|
|
|
|
+ setAlwaysAllowModeSwitch(value)
|
|
|
|
|
+ break
|
|
|
|
|
+ case "alwaysAllowSubtasks":
|
|
|
|
|
+ setAlwaysAllowSubtasks(value)
|
|
|
|
|
+ break
|
|
|
|
|
+ case "alwaysApproveResubmit":
|
|
|
|
|
+ setAlwaysApproveResubmit(value)
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
},
|
|
},
|
|
|
- {
|
|
|
|
|
- id: "subtasks",
|
|
|
|
|
- label: t("chat:autoApprove.actions.subtasks.label"),
|
|
|
|
|
- enabled: alwaysAllowSubtasks ?? false,
|
|
|
|
|
- description: t("chat:autoApprove.actions.subtasks.description"),
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: "retryRequests",
|
|
|
|
|
- label: t("chat:autoApprove.actions.retryRequests.label"),
|
|
|
|
|
- enabled: alwaysApproveResubmit ?? false,
|
|
|
|
|
- description: t("chat:autoApprove.actions.retryRequests.description"),
|
|
|
|
|
- },
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ [
|
|
|
|
|
+ setAlwaysAllowReadOnly,
|
|
|
|
|
+ setAlwaysAllowWrite,
|
|
|
|
|
+ setAlwaysAllowExecute,
|
|
|
|
|
+ setAlwaysAllowBrowser,
|
|
|
|
|
+ setAlwaysAllowMcp,
|
|
|
|
|
+ setAlwaysAllowModeSwitch,
|
|
|
|
|
+ setAlwaysAllowSubtasks,
|
|
|
|
|
+ setAlwaysApproveResubmit,
|
|
|
|
|
+ ],
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
- const toggleExpanded = useCallback(() => {
|
|
|
|
|
- setIsExpanded((prev) => !prev)
|
|
|
|
|
- }, [])
|
|
|
|
|
|
|
+ const toggleExpanded = useCallback(() => setIsExpanded((prev) => !prev), [])
|
|
|
|
|
+
|
|
|
|
|
+ const toggles = useMemo(
|
|
|
|
|
+ () => ({
|
|
|
|
|
+ alwaysAllowReadOnly: alwaysAllowReadOnly,
|
|
|
|
|
+ alwaysAllowWrite: alwaysAllowWrite,
|
|
|
|
|
+ alwaysAllowExecute: alwaysAllowExecute,
|
|
|
|
|
+ alwaysAllowBrowser: alwaysAllowBrowser,
|
|
|
|
|
+ alwaysAllowMcp: alwaysAllowMcp,
|
|
|
|
|
+ alwaysAllowModeSwitch: alwaysAllowModeSwitch,
|
|
|
|
|
+ alwaysAllowSubtasks: alwaysAllowSubtasks,
|
|
|
|
|
+ alwaysApproveResubmit: alwaysApproveResubmit,
|
|
|
|
|
+ }),
|
|
|
|
|
+ [
|
|
|
|
|
+ alwaysAllowReadOnly,
|
|
|
|
|
+ alwaysAllowWrite,
|
|
|
|
|
+ alwaysAllowExecute,
|
|
|
|
|
+ alwaysAllowBrowser,
|
|
|
|
|
+ alwaysAllowMcp,
|
|
|
|
|
+ alwaysAllowModeSwitch,
|
|
|
|
|
+ alwaysAllowSubtasks,
|
|
|
|
|
+ alwaysApproveResubmit,
|
|
|
|
|
+ ],
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
- const enabledActionsList = actions
|
|
|
|
|
- .filter((action) => action.enabled)
|
|
|
|
|
- .map((action) => action.label)
|
|
|
|
|
|
|
+ const enabledActionsList = Object.entries(toggles)
|
|
|
|
|
+ .filter(([_key, value]) => !!value)
|
|
|
|
|
+ .map(([key]) => t(autoApproveSettingsConfig[key as AutoApproveSetting].labelKey))
|
|
|
.join(", ")
|
|
.join(", ")
|
|
|
|
|
|
|
|
- // Individual checkbox handlers - each one only updates its own state.
|
|
|
|
|
- const handleReadOnlyChange = useCallback(() => {
|
|
|
|
|
- const newValue = !(alwaysAllowReadOnly ?? false)
|
|
|
|
|
- setAlwaysAllowReadOnly(newValue)
|
|
|
|
|
- vscode.postMessage({ type: "alwaysAllowReadOnly", bool: newValue })
|
|
|
|
|
- }, [alwaysAllowReadOnly, setAlwaysAllowReadOnly])
|
|
|
|
|
-
|
|
|
|
|
- const handleWriteChange = useCallback(() => {
|
|
|
|
|
- const newValue = !(alwaysAllowWrite ?? false)
|
|
|
|
|
- setAlwaysAllowWrite(newValue)
|
|
|
|
|
- vscode.postMessage({ type: "alwaysAllowWrite", bool: newValue })
|
|
|
|
|
- }, [alwaysAllowWrite, setAlwaysAllowWrite])
|
|
|
|
|
-
|
|
|
|
|
- const handleExecuteChange = useCallback(() => {
|
|
|
|
|
- const newValue = !(alwaysAllowExecute ?? false)
|
|
|
|
|
- setAlwaysAllowExecute(newValue)
|
|
|
|
|
- vscode.postMessage({ type: "alwaysAllowExecute", bool: newValue })
|
|
|
|
|
- }, [alwaysAllowExecute, setAlwaysAllowExecute])
|
|
|
|
|
-
|
|
|
|
|
- const handleBrowserChange = useCallback(() => {
|
|
|
|
|
- const newValue = !(alwaysAllowBrowser ?? false)
|
|
|
|
|
- setAlwaysAllowBrowser(newValue)
|
|
|
|
|
- vscode.postMessage({ type: "alwaysAllowBrowser", bool: newValue })
|
|
|
|
|
- }, [alwaysAllowBrowser, setAlwaysAllowBrowser])
|
|
|
|
|
-
|
|
|
|
|
- const handleMcpChange = useCallback(() => {
|
|
|
|
|
- const newValue = !(alwaysAllowMcp ?? false)
|
|
|
|
|
- setAlwaysAllowMcp(newValue)
|
|
|
|
|
- vscode.postMessage({ type: "alwaysAllowMcp", bool: newValue })
|
|
|
|
|
- }, [alwaysAllowMcp, setAlwaysAllowMcp])
|
|
|
|
|
-
|
|
|
|
|
- const handleModeSwitchChange = useCallback(() => {
|
|
|
|
|
- const newValue = !(alwaysAllowModeSwitch ?? false)
|
|
|
|
|
- setAlwaysAllowModeSwitch(newValue)
|
|
|
|
|
- vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: newValue })
|
|
|
|
|
- }, [alwaysAllowModeSwitch, setAlwaysAllowModeSwitch])
|
|
|
|
|
-
|
|
|
|
|
- const handleSubtasksChange = useCallback(() => {
|
|
|
|
|
- const newValue = !(alwaysAllowSubtasks ?? false)
|
|
|
|
|
- setAlwaysAllowSubtasks(newValue)
|
|
|
|
|
- vscode.postMessage({ type: "alwaysAllowSubtasks", bool: newValue })
|
|
|
|
|
- }, [alwaysAllowSubtasks, setAlwaysAllowSubtasks])
|
|
|
|
|
-
|
|
|
|
|
- const handleRetryChange = useCallback(() => {
|
|
|
|
|
- const newValue = !(alwaysApproveResubmit ?? false)
|
|
|
|
|
- setAlwaysApproveResubmit(newValue)
|
|
|
|
|
- vscode.postMessage({ type: "alwaysApproveResubmit", bool: newValue })
|
|
|
|
|
- }, [alwaysApproveResubmit, setAlwaysApproveResubmit])
|
|
|
|
|
-
|
|
|
|
|
- const handleOpenSettings = useCallback(() => {
|
|
|
|
|
- window.postMessage({
|
|
|
|
|
- type: "action",
|
|
|
|
|
- action: "settingsButtonClicked",
|
|
|
|
|
- values: { section: "autoApprove" },
|
|
|
|
|
- })
|
|
|
|
|
- }, [])
|
|
|
|
|
-
|
|
|
|
|
- // Map action IDs to their specific handlers.
|
|
|
|
|
- const actionHandlers: Record<AutoApproveAction["id"], () => void> = {
|
|
|
|
|
- readFiles: handleReadOnlyChange,
|
|
|
|
|
- editFiles: handleWriteChange,
|
|
|
|
|
- executeCommands: handleExecuteChange,
|
|
|
|
|
- useBrowser: handleBrowserChange,
|
|
|
|
|
- useMcp: handleMcpChange,
|
|
|
|
|
- switchModes: handleModeSwitchChange,
|
|
|
|
|
- subtasks: handleSubtasksChange,
|
|
|
|
|
- retryRequests: handleRetryChange,
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const handleOpenSettings = useCallback(
|
|
|
|
|
+ () =>
|
|
|
|
|
+ window.postMessage({ type: "action", action: "settingsButtonClicked", values: { section: "autoApprove" } }),
|
|
|
|
|
+ [],
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<div
|
|
<div
|
|
@@ -250,6 +181,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
{isExpanded && (
|
|
{isExpanded && (
|
|
|
<div className="flex flex-col gap-2">
|
|
<div className="flex flex-col gap-2">
|
|
|
<div
|
|
<div
|
|
@@ -264,27 +196,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|
|
}}
|
|
}}
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
- <div className="grid grid-cols-2 [@media(min-width:320px)]:grid-cols-4 gap-2">
|
|
|
|
|
- {actions.map((action) => {
|
|
|
|
|
- const codicon = ICON_MAP[action.id] || "question"
|
|
|
|
|
- return (
|
|
|
|
|
- <Button
|
|
|
|
|
- key={action.id}
|
|
|
|
|
- variant={action.enabled ? "default" : "ghost"}
|
|
|
|
|
- onClick={(e) => {
|
|
|
|
|
- e.stopPropagation()
|
|
|
|
|
- actionHandlers[action.id]()
|
|
|
|
|
- }}
|
|
|
|
|
- title={action.description}
|
|
|
|
|
- className="h-12">
|
|
|
|
|
- <span className="flex flex-col items-center gap-1">
|
|
|
|
|
- <span className={`codicon codicon-${codicon}`} />
|
|
|
|
|
- <span className="text-sm text-center">{action.label}</span>
|
|
|
|
|
- </span>
|
|
|
|
|
- </Button>
|
|
|
|
|
- )
|
|
|
|
|
- })}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <AutoApproveToggle {...toggles} onToggle={onAutoApproveToggle} />
|
|
|
</div>
|
|
</div>
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|