3e237e177a
* feat: add code-walkthrough backend (MCP tool, service, persistence, WS events) * feat: render agent code walkthroughs as line-anchored cards + editor window * test: add code-walkthrough re-emit mock-agent scenario * fix: rework code-walkthrough UX (floating card, line reveal, minimize, clickable file) * fix: improve code walkthrough editor UX * fix: backfill walkthrough launcher after websocket connect * fix: improve walkthrough requests and editor anchors * fix: clear walkthrough highlights on close * feat: add walkthrough discard and prompt customization * fix: send walkthrough requests through saved prompt * fix: support postgres built-in prompt seeding * fix: address walkthrough review feedback * fix: address walkthrough review follow-ups * fix: harden walkthrough lifecycle races * fix: reuse walkthrough notification cleanup * fix: guard stale walkthrough file opens * fix: abort stale file opens before paint * fix: stabilize github settings e2e readiness * fix: use stable github settings e2e selector
126 lines
3.6 KiB
TypeScript
126 lines
3.6 KiB
TypeScript
import { useCallback, type ReactNode } from "react";
|
|
import type { DiffLineAnnotation } from "@pierre/diffs";
|
|
import type { DiffComment } from "@/lib/diff/types";
|
|
import { CommentForm } from "./comment-form";
|
|
import { CommentDisplay } from "./comment-display";
|
|
import { HunkActionBar } from "./hunk-action-bar";
|
|
import { WalkthroughStepCard } from "./walkthrough-step-card";
|
|
|
|
type AnnotationMetadata = {
|
|
type: "comment" | "new-comment-form" | "hunk-actions" | "walkthrough-step";
|
|
comment?: DiffComment;
|
|
isEditing?: boolean;
|
|
changeBlockId?: string;
|
|
};
|
|
|
|
type UseAnnotationRendererOpts = {
|
|
handleRevertBlock: (changeBlockId: string) => Promise<void>;
|
|
onButtonEnter: () => void;
|
|
onButtonLeave: () => void;
|
|
handleCommentSubmit: (content: string) => void;
|
|
handleCommentSubmitAndRun?: (content: string) => void;
|
|
handleCommentUpdate: (commentId: string, content: string) => void;
|
|
handleCommentDelete: (commentId: string) => void;
|
|
handleCommentRun?: (comment: DiffComment) => void;
|
|
setShowCommentForm: (show: boolean) => void;
|
|
setSelectedLines: (lines: null) => void;
|
|
setEditingComment: (id: string | null) => void;
|
|
};
|
|
|
|
export type { AnnotationMetadata };
|
|
|
|
export function useAnnotationRenderer(opts: UseAnnotationRendererOpts) {
|
|
const {
|
|
handleRevertBlock,
|
|
onButtonEnter,
|
|
onButtonLeave,
|
|
handleCommentSubmit,
|
|
handleCommentSubmitAndRun,
|
|
handleCommentUpdate,
|
|
handleCommentDelete,
|
|
handleCommentRun,
|
|
setShowCommentForm,
|
|
setSelectedLines,
|
|
setEditingComment,
|
|
} = opts;
|
|
|
|
return useCallback(
|
|
(annotation: DiffLineAnnotation<AnnotationMetadata>): ReactNode => {
|
|
const { type, comment, isEditing, changeBlockId } = annotation.metadata;
|
|
|
|
if (type === "walkthrough-step") {
|
|
return <WalkthroughStepCard key="walkthrough-step" />;
|
|
}
|
|
|
|
if (type === "hunk-actions" && changeBlockId) {
|
|
return (
|
|
<HunkActionBar
|
|
key={changeBlockId}
|
|
changeBlockId={changeBlockId}
|
|
onRevert={() => handleRevertBlock(changeBlockId)}
|
|
onMouseEnter={onButtonEnter}
|
|
onMouseLeave={onButtonLeave}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (type === "new-comment-form") {
|
|
return (
|
|
<div className="my-1 px-2">
|
|
<CommentForm
|
|
onSubmit={handleCommentSubmit}
|
|
onSubmitAndRun={handleCommentSubmitAndRun}
|
|
onCancel={() => {
|
|
setShowCommentForm(false);
|
|
setSelectedLines(null);
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (isEditing && comment) {
|
|
return (
|
|
<div className="my-1 px-2">
|
|
<CommentForm
|
|
initialContent={comment.text}
|
|
onSubmit={(content) => handleCommentUpdate(comment.id, content)}
|
|
onCancel={() => setEditingComment(null)}
|
|
isEditing
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (comment) {
|
|
return (
|
|
<div className="my-1 px-2">
|
|
<CommentDisplay
|
|
comment={comment}
|
|
onDelete={() => handleCommentDelete(comment.id)}
|
|
onEdit={() => setEditingComment(comment.id)}
|
|
onRun={handleCommentRun ? () => handleCommentRun(comment) : undefined}
|
|
showCode={false}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return null;
|
|
},
|
|
[
|
|
setEditingComment,
|
|
handleCommentDelete,
|
|
handleCommentRun,
|
|
handleCommentUpdate,
|
|
handleCommentSubmit,
|
|
handleCommentSubmitAndRun,
|
|
handleRevertBlock,
|
|
onButtonEnter,
|
|
onButtonLeave,
|
|
setShowCommentForm,
|
|
setSelectedLines,
|
|
],
|
|
);
|
|
}
|