diff --git a/.changeset/chilly-bugs-pay.md b/.changeset/chilly-bugs-pay.md new file mode 100644 index 00000000000..b30f8241ef7 --- /dev/null +++ b/.changeset/chilly-bugs-pay.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Delete task confirmation enhancements diff --git a/webview-ui/src/components/chat/TaskHeader.tsx b/webview-ui/src/components/chat/TaskHeader.tsx index fb7db6f6173..319a9aeccd3 100644 --- a/webview-ui/src/components/chat/TaskHeader.tsx +++ b/webview-ui/src/components/chat/TaskHeader.tsx @@ -3,15 +3,18 @@ import { useWindowSize } from "react-use" import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" import prettyBytes from "pretty-bytes" +import { vscode } from "@/utils/vscode" +import { formatLargeNumber } from "@/utils/format" +import { Button } from "@/components/ui" + import { ClineMessage } from "../../../../src/shared/ExtensionMessage" +import { mentionRegexGlobal } from "../../../../src/shared/context-mentions" +import { HistoryItem } from "../../../../src/shared/HistoryItem" + import { useExtensionState } from "../../context/ExtensionStateContext" -import { vscode } from "../../utils/vscode" import Thumbnails from "../common/Thumbnails" -import { mentionRegexGlobal } from "../../../../src/shared/context-mentions" -import { formatLargeNumber } from "../../utils/format" import { normalizeApiConfiguration } from "../settings/ApiOptions" -import { Button } from "../ui" -import { HistoryItem } from "../../../../src/shared/HistoryItem" +import { DeleteTaskDialog } from "../history/DeleteTaskDialog" interface TaskHeaderProps { task: ClineMessage @@ -46,7 +49,21 @@ const TaskHeader: React.FC = ({ const contextWindow = selectedModelInfo?.contextWindow || 1 /* - When dealing with event listeners in React components that depend on state variables, we face a challenge. We want our listener to always use the most up-to-date version of a callback function that relies on current state, but we don't want to constantly add and remove event listeners as that function updates. This scenario often arises with resize listeners or other window events. Simply adding the listener in a useEffect with an empty dependency array risks using stale state, while including the callback in the dependencies can lead to unnecessary re-registrations of the listener. There are react hook libraries that provide a elegant solution to this problem by utilizing the useRef hook to maintain a reference to the latest callback function without triggering re-renders or effect re-runs. This approach ensures that our event listener always has access to the most current state while minimizing performance overhead and potential memory leaks from multiple listener registrations. + When dealing with event listeners in React components that depend on state + variables, we face a challenge. We want our listener to always use the most + up-to-date version of a callback function that relies on current state, but + we don't want to constantly add and remove event listeners as that function + updates. This scenario often arises with resize listeners or other window + events. Simply adding the listener in a useEffect with an empty dependency + array risks using stale state, while including the callback in the + dependencies can lead to unnecessary re-registrations of the listener. There + are react hook libraries that provide a elegant solution to this problem by + utilizing the useRef hook to maintain a reference to the latest callback + function without triggering re-renders or effect re-runs. This approach + ensures that our event listener always has access to the most current state + while minimizing performance overhead and potential memory leaks from + multiple listener registrations. + Sources - https://usehooks-ts.com/react-hook/use-event-listener - https://streamich.github.io/react-use/?path=/story/sensors-useevent--docs @@ -350,27 +367,48 @@ export const highlightMentions = (text?: string, withShadow = true) => { }) } -const TaskActions = ({ item }: { item: HistoryItem | undefined }) => ( -
- - {!!item?.size && item.size > 0 && ( +const TaskActions = ({ item }: { item: HistoryItem | undefined }) => { + const [deleteTaskId, setDeleteTaskId] = useState(null) + + return ( +
- )} -
-) + {!!item?.size && item.size > 0 && ( + <> + + {deleteTaskId && ( + !open && setDeleteTaskId(null)} + open + /> + )} + + )} +
+ ) +} const ContextWindowProgress = ({ contextWindow, contextTokens }: { contextWindow: number; contextTokens: number }) => ( <> diff --git a/webview-ui/src/components/history/DeleteTaskDialog.tsx b/webview-ui/src/components/history/DeleteTaskDialog.tsx index b40adeae3de..31d85abd370 100644 --- a/webview-ui/src/components/history/DeleteTaskDialog.tsx +++ b/webview-ui/src/components/history/DeleteTaskDialog.tsx @@ -1,4 +1,7 @@ -import React from "react" +import { useCallback, useEffect } from "react" +import { useKeyPress } from "react-use" +import { AlertDialogProps } from "@radix-ui/react-alert-dialog" + import { AlertDialog, AlertDialogAction, @@ -8,25 +11,36 @@ import { AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, -} from "@/components/ui/alert-dialog" -import { Button } from "@/components/ui" + Button, +} from "@/components/ui" + import { vscode } from "@/utils/vscode" -interface DeleteTaskDialogProps { +interface DeleteTaskDialogProps extends AlertDialogProps { taskId: string - open: boolean - onOpenChange: (open: boolean) => void } -export const DeleteTaskDialog = ({ taskId, open, onOpenChange }: DeleteTaskDialogProps) => { - const handleDelete = () => { - vscode.postMessage({ type: "deleteTaskWithId", text: taskId }) - onOpenChange(false) - } +export const DeleteTaskDialog = ({ taskId, ...props }: DeleteTaskDialogProps) => { + const [isEnterPressed] = useKeyPress("Enter") + + const { onOpenChange } = props + + const onDelete = useCallback(() => { + if (taskId) { + vscode.postMessage({ type: "deleteTaskWithId", text: taskId }) + onOpenChange?.(false) + } + }, [taskId, onOpenChange]) + + useEffect(() => { + if (taskId && isEnterPressed) { + onDelete() + } + }, [taskId, isEnterPressed, onDelete]) return ( - - + + onOpenChange?.(false)}> Delete Task @@ -38,7 +52,7 @@ export const DeleteTaskDialog = ({ taskId, open, onOpenChange }: DeleteTaskDialo - diff --git a/webview-ui/src/components/history/HistoryView.tsx b/webview-ui/src/components/history/HistoryView.tsx index ca60e1fcb89..49d71e5ddd9 100644 --- a/webview-ui/src/components/history/HistoryView.tsx +++ b/webview-ui/src/components/history/HistoryView.tsx @@ -38,13 +38,7 @@ const HistoryView = ({ onDone }: HistoryViewProps) => { vscode.postMessage({ type: "showTaskWithId", text: id }) } - const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) - const [taskToDelete, setTaskToDelete] = useState(null) - - const handleDeleteHistoryItem = (id: string) => { - setTaskToDelete(id) - setDeleteDialogOpen(true) - } + const [deleteTaskId, setDeleteTaskId] = useState(null) const formatDate = (timestamp: number) => { const date = new Date(timestamp) @@ -230,10 +224,15 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {