diff --git a/apps/code/src/renderer/features/code-review/components/CloudReviewPage.tsx b/apps/code/src/renderer/features/code-review/components/CloudReviewPage.tsx index 9c1c88f64..8cae2449e 100644 --- a/apps/code/src/renderer/features/code-review/components/CloudReviewPage.tsx +++ b/apps/code/src/renderer/features/code-review/components/CloudReviewPage.tsx @@ -4,12 +4,13 @@ import { extractCloudFileDiff, type ParsedToolCall, } from "@features/task-detail/utils/cloudToolChanges"; -import type { FileDiffOptions } from "@pierre/diffs"; -import { MultiFileDiff } from "@pierre/diffs/react"; import { Flex, Spinner, Text } from "@radix-ui/themes"; import type { ChangedFile, Task } from "@shared/types"; import type { AcpMessage } from "@shared/types/session-events"; import { useMemo } from "react"; +import { useReviewComment } from "../hooks/useReviewComment"; +import type { DiffOptions, OnCommentCallback } from "../types"; +import { InteractiveFileDiff } from "./InteractiveFileDiff"; import { DeferredDiffPlaceholder, DiffFileHeader, @@ -33,6 +34,7 @@ export function CloudReviewPage({ taskId, task }: CloudReviewPageProps) { changedFiles, isLoading, } = useCloudChangedFiles(taskId, task); + const onComment = useReviewComment(taskId); const events = session?.events ?? EMPTY_EVENTS; const summary = useMemo(() => buildCloudEventSummary(events), [events]); @@ -117,6 +119,7 @@ export function CloudReviewPage({ taskId, task }: CloudReviewPageProps) { options={diffOptions} collapsed={isCollapsed} onToggle={() => toggleFile(file.path)} + onComment={onComment} /> ); @@ -131,12 +134,14 @@ function CloudFileDiff({ options, collapsed, onToggle, + onComment, }: { file: ChangedFile; toolCalls: Map; - options: FileDiffOptions; + options: DiffOptions; collapsed: boolean; onToggle: () => void; + onComment: OnCommentCallback; }) { const diff = useMemo( () => extractCloudFileDiff(toolCalls, file.path), @@ -154,10 +159,11 @@ function CloudFileDiff({ ); return ( - ( void; + onCancel: () => void; +} + +export function CommentAnnotation({ + onSubmit, + onCancel, +}: CommentAnnotationProps) { + const textareaRef = useRef(null); + + const setTextareaRef = useCallback((el: HTMLTextAreaElement | null) => { + ( + textareaRef as React.MutableRefObject + ).current = el; + if (el) { + requestAnimationFrame(() => el.focus()); + } + }, []); + + const handleSubmit = useCallback(() => { + const text = textareaRef.current?.value?.trim(); + if (text) { + onSubmit(text); + } + }, [onSubmit]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + handleSubmit(); + } + if (e.key === "Escape") { + e.preventDefault(); + onCancel(); + } + }, + [handleSubmit, onCancel], + ); + + return ( +
+