test(ui): reply-to-comment scenario in the Issue Chat UX Lab

Adds a fixture-backed reply section to /tests/ux/chat exercising the P3 states:
composer reply chip (seeded via localStorage), sent quoted block, and the
deleted-source tombstone. Gives QA a live in-app surface to test against.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
DottaandClaude Opus 4.8 committed 2026-07-13 09:11:14 +00:00
1 parent 0fb4f879f2
commit ad90fa2ebe
2 files changed
+112

No files matched your search

+69
View File
@@ -338,6 +338,75 @@ export const issueChatUxReviewEvents: IssueTimelineEvent[] = [
},
];
/**
* Reply-to-comment (PAP-13802 P3) scenario: a sent reply with a quoted block, a reply whose
* source was deleted (tombstone), and the source comments they point back to. Seed
* {@link issueChatUxReplyDraftKey} in localStorage to also render the composer reply chip.
*/
export const issueChatUxReplyDraftKey = "paperclip:issue-comment-draft:issue-ux-reply";
export const issueChatUxReplyComments: IssueChatComment[] = [
createComment({
id: "comment-reply-source",
authorAgentId: primaryAgent.id,
authorUserId: null,
body: "I moved the composer reply chip above the editor and clamp the quoted source to 200 chars so long comments stay one line.",
createdAt: new Date("2026-04-06T13:00:00.000Z"),
updatedAt: new Date("2026-04-06T13:00:00.000Z"),
runId: "run-reply-1",
runAgentId: primaryAgent.id,
}),
createComment({
id: "comment-reply-sent",
body: "Nice — can you make the quoted block jump to the original when clicked?",
createdAt: new Date("2026-04-06T13:02:00.000Z"),
updatedAt: new Date("2026-04-06T13:02:00.000Z"),
metadata: {
version: 1,
sections: [],
replyTo: {
commentId: "comment-reply-source",
authorType: "agent",
authorAgentId: primaryAgent.id,
authorUserId: null,
excerpt: "I moved the composer reply chip above the editor and clamp the quoted source to 200 chars so long comments stay one line.",
excerptTruncated: true,
},
},
}),
createComment({
id: "comment-reply-deleted-source",
body: "This source comment was removed after the reply was posted.",
createdAt: new Date("2026-04-06T13:04:00.000Z"),
updatedAt: new Date("2026-04-06T13:04:30.000Z"),
deletedAt: new Date("2026-04-06T13:05:00.000Z"),
deletedByType: "user",
deletedByUserId: "user-1",
}),
createComment({
id: "comment-reply-tombstone",
authorAgentId: reviewAgent.id,
authorUserId: null,
body: "Done — and when the source is deleted the quoted header falls back to a tombstone.",
createdAt: new Date("2026-04-06T13:06:00.000Z"),
updatedAt: new Date("2026-04-06T13:06:00.000Z"),
runId: "run-reply-2",
runAgentId: reviewAgent.id,
metadata: {
version: 1,
sections: [],
replyTo: {
commentId: "comment-reply-deleted-source",
authorType: "user",
authorAgentId: null,
authorUserId: "user-1",
excerpt: "This source comment was removed after the reply was posted.",
excerptTruncated: false,
},
},
}),
];
export const issueChatUxFeedbackVotes: FeedbackVote[] = [
{
id: "feedback-1",
+43
View File
@@ -16,6 +16,8 @@ import {
issueChatUxLiveRuns,
issueChatUxMentions,
issueChatUxReassignOptions,
issueChatUxReplyComments,
issueChatUxReplyDraftKey,
issueChatUxReviewComments,
issueChatUxReviewEvents,
issueChatUxSubmittingComments,
@@ -143,6 +145,24 @@ function RotatingReasoningDemo({ intervalMs = 2200 }: { intervalMs?: number }) {
export function IssueChatUxLab() {
const [showComposer, setShowComposer] = useState(true);
// Seed a composer reply draft so the reply-scenario section renders the chip on load.
useEffect(() => {
try {
localStorage.setItem(
`${issueChatUxReplyDraftKey}:reply`,
JSON.stringify({
commentId: "comment-reply-source",
authorName: "CodexCoder",
excerpt:
"I moved the composer reply chip above the editor and clamp the quoted source to 200 chars so long comments stay one line.",
excerptTruncated: true,
}),
);
} catch {
// Ignore localStorage failures in the lab preview.
}
}, []);
return (
<div className="space-y-6">
<div className="overflow-hidden rounded-(--rad-32) border border-border/70 bg-[linear-gradient(135deg,rgba(8,145,178,0.10),transparent_28%),linear-gradient(180deg,rgba(245,158,11,0.10),transparent_44%),var(--background)] shadow-[0_30px_80px_rgba(15,23,42,0.10)]">
@@ -296,6 +316,29 @@ export function IssueChatUxLab() {
/>
</LabSection>
<LabSection
id="reply-to-comment"
eyebrow="Reply to comment"
title="Reply chip, quoted block, and tombstone"
description="PAP-13802 P3: hover a bubble to reveal Reply, the composer shows a quoted/clamped source chip (click to jump to the original, X or Escape to clear), sent replies render a quoted header above the body, and a reply whose source was deleted falls back to an 'Original comment deleted' tombstone."
accentClassName="bg-[linear-gradient(180deg,rgba(16,185,129,0.06),transparent_28%),var(--background)]"
>
<IssueChatThread
comments={issueChatUxReplyComments}
linkedRuns={[]}
timelineEvents={[]}
issueStatus="in_progress"
agentMap={issueChatUxAgentMap}
currentUserId="user-1"
onAdd={noop}
onVote={noop}
draftKey={issueChatUxReplyDraftKey}
mentions={issueChatUxMentions}
showComposer={showComposer}
enableLiveTranscriptPolling={false}
/>
</LabSection>
<LabSection
eyebrow="Submitting state"
title="Pending message bubble"