diff --git a/apps/web/src/components/DiffPanel.tsx b/apps/web/src/components/DiffPanel.tsx index f39af581d5a..e41ba9c2440 100644 --- a/apps/web/src/components/DiffPanel.tsx +++ b/apps/web/src/components/DiffPanel.tsx @@ -38,7 +38,7 @@ import { resolveThreadRouteRef } from "../threadRoutes"; import { useClientSettings } from "../hooks/useSettings"; import { formatShortTimestamp } from "../timestampFormat"; import { DiffPanelLoadingState, DiffPanelShell, type DiffPanelMode } from "./DiffPanelShell"; -import { AnnotatableCodeView, type AnnotatableCodeViewHandle } from "./diffs/AnnotatableFileDiff"; +import { AnnotatableCodeView, type AnnotatableCodeViewHandle } from "./diffs/AnnotatableCodeView"; import { ToggleGroup, Toggle } from "./ui/toggle-group"; import { Switch } from "./ui/switch"; import { diff --git a/apps/web/src/components/diffs/AnnotatableFileDiff.tsx b/apps/web/src/components/diffs/AnnotatableCodeView.tsx similarity index 60% rename from apps/web/src/components/diffs/AnnotatableFileDiff.tsx rename to apps/web/src/components/diffs/AnnotatableCodeView.tsx index f74b1e59aa3..6cea64fb570 100644 --- a/apps/web/src/components/diffs/AnnotatableFileDiff.tsx +++ b/apps/web/src/components/diffs/AnnotatableCodeView.tsx @@ -6,13 +6,7 @@ import type { FileDiffMetadata, SelectedLineRange, } from "@pierre/diffs"; -import { - CodeView, - type CodeViewHandle, - type CodeViewProps, - FileDiff, - type FileDiffProps, -} from "@pierre/diffs/react"; +import { CodeView, type CodeViewHandle, type CodeViewProps } from "@pierre/diffs/react"; import type { ScopedThreadRef } from "@t3tools/contracts"; import { useCallback, useMemo, useState, type ReactNode, type Ref } from "react"; @@ -76,178 +70,6 @@ function appendAnnotationEntry( ); } -interface AnnotatableFileDiffProps { - fileDiff: FileDiffMetadata; - filePath: string; - sectionId: string; - sectionTitle: string; - composerDraftTarget: ScopedThreadRef | DraftId; - options: FileDiffProps["options"]; - renderHeaderPrefix: (fileDiff: FileDiffMetadata) => ReactNode; -} - -export function AnnotatableFileDiff({ - fileDiff, - filePath, - sectionId, - sectionTitle, - composerDraftTarget, - options, - renderHeaderPrefix, -}: AnnotatableFileDiffProps) { - const addReviewComment = useComposerDraftStore((store) => store.addReviewComment); - const removeReviewComment = useComposerDraftStore((store) => store.removeReviewComment); - const reviewComments = useComposerDraftStore( - (store) => store.getComposerDraft(composerDraftTarget)?.reviewComments ?? EMPTY_REVIEW_COMMENTS, - ); - const [selectedRange, setSelectedRange] = useState(null); - const [draftAnnotation, setDraftAnnotation] = useState(null); - const persistedAnnotations = useMemo( - () => - reviewComments - .filter( - (comment) => - comment.sectionId === sectionId && - comment.filePath === filePath && - (comment.fenceLanguage ?? "diff") === "diff", - ) - .reduce((annotations, comment) => { - const range = restoreDiffReviewCommentRange(fileDiff, comment); - if (!range) return annotations; - return appendAnnotationEntry(annotations, range, { - id: comment.id, - kind: "comment", - range, - rangeLabel: comment.rangeLabel, - text: comment.text, - }); - }, []), - [fileDiff, filePath, reviewComments, sectionId], - ); - const lineAnnotations = useMemo( - () => (draftAnnotation ? [...persistedAnnotations, draftAnnotation] : persistedAnnotations), - [draftAnnotation, persistedAnnotations], - ); - - const removeAnnotationEntry = useCallback( - (entryId: string) => { - setSelectedRange(null); - if ( - draftAnnotation?.metadata.entries.some( - (entry) => entry.id === entryId && entry.kind === "draft", - ) - ) { - setDraftAnnotation(null); - return; - } - removeReviewComment(composerDraftTarget, entryId); - }, - [composerDraftTarget, draftAnnotation, removeReviewComment], - ); - - const submitAnnotationEntry = useCallback( - (entryId: string, text: string) => { - const entry = draftAnnotation?.metadata.entries.find((candidate) => candidate.id === entryId); - if (!entry) return; - - const comment = buildDiffReviewComment({ - id: entry.id, - sectionId, - sectionTitle, - filePath, - fileDiff, - range: entry.range, - text, - }); - if (comment) { - addReviewComment(composerDraftTarget, comment); - } - setSelectedRange(null); - setDraftAnnotation(null); - }, - [ - addReviewComment, - composerDraftTarget, - fileDiff, - filePath, - draftAnnotation, - sectionId, - sectionTitle, - ], - ); - - const beginComment = useCallback( - (range: SelectedLineRange) => { - const id = nextFileCommentId(); - const comment = buildDiffReviewComment({ - id, - sectionId, - sectionTitle, - filePath, - fileDiff, - range, - text: "", - }); - if (!comment) return; - - const draftEntry: DiffCommentAnnotationEntry = { - id, - kind: "draft", - range, - rangeLabel: comment.rangeLabel, - text: "", - }; - setDraftAnnotation({ - side: annotationSide(range), - lineNumber: range.end, - metadata: { entries: [draftEntry] }, - }); - }, - [fileDiff, filePath, sectionId, sectionTitle], - ); - - const hasOpenCommentForm = draftAnnotation !== null; - const handleLineSelectionEnd = useCallback( - (range: SelectedLineRange | null) => { - setSelectedRange(range); - if (range) beginComment(range); - }, - [beginComment], - ); - - return ( - - fileDiff={fileDiff} - renderHeaderPrefix={renderHeaderPrefix} - options={{ - ...options, - enableGutterUtility: !hasOpenCommentForm, - enableLineSelection: !hasOpenCommentForm, - onGutterUtilityClick: setSelectedRange, - onLineSelectionChange: setSelectedRange, - onLineSelectionEnd: handleLineSelectionEnd, - }} - selectedLines={selectedRange} - lineAnnotations={lineAnnotations} - renderAnnotation={(annotation) => ( -
- {annotation.metadata.entries.map((entry) => ( - removeAnnotationEntry(entry.id)} - onComment={(text) => submitAnnotationEntry(entry.id, text)} - onDelete={() => removeAnnotationEntry(entry.id)} - /> - ))} -
- )} - /> - ); -} - interface AnnotatableCodeViewProps { files: ReadonlyArray<{ fileDiff: FileDiffMetadata;