From cdf5b4570ad54b376bbc1a9aa159f94843154467 Mon Sep 17 00:00:00 2001 From: Julian Benegas Date: Mon, 8 Jun 2026 16:57:45 +0000 Subject: [PATCH] Disable threaded comment replies --- .../[postNumber]/comment-thread-client.tsx | 26 +--- .../[repo]/[postNumber]/comment-thread.tsx | 128 +----------------- .../app/[owner]/[repo]/[postNumber]/page.tsx | 1 - apps/web/lib/actions/posts.ts | 11 +- apps/web/lib/utils/comment-numbers.test.ts | 18 +++ apps/web/lib/utils/comment-numbers.ts | 19 +-- 6 files changed, 31 insertions(+), 172 deletions(-) create mode 100644 apps/web/lib/utils/comment-numbers.test.ts diff --git a/apps/web/app/[owner]/[repo]/[postNumber]/comment-thread-client.tsx b/apps/web/app/[owner]/[repo]/[postNumber]/comment-thread-client.tsx index ff202b2..4d9f2f6 100644 --- a/apps/web/app/[owner]/[repo]/[postNumber]/comment-thread-client.tsx +++ b/apps/web/app/[owner]/[repo]/[postNumber]/comment-thread-client.tsx @@ -1,8 +1,7 @@ "use client" import type { InferSelectModel } from "drizzle-orm" -import { useEffect, useMemo, useState } from "react" -import { authClient } from "@/lib/auth-client" +import { useEffect, useMemo } from "react" import type { comments as commentsSchema, mentions as mentionsSchema, @@ -22,13 +21,6 @@ type AuthorInfo = { isLlm: boolean } -type AskingOption = { - id: string - name: string - image?: string | null - isDefault?: boolean -} - export function CommentThreadClient({ owner, repo, @@ -38,7 +30,6 @@ export function CommentThreadClient({ reactions, rootCommentId, commentNumbers, - askingOptions, }: { owner: string repo: string @@ -48,10 +39,7 @@ export function CommentThreadClient({ reactions: Reaction[] rootCommentId: string | null commentNumbers: Map - askingOptions: AskingOption[] }) { - const [replyingToId, setReplyingToId] = useState(null) - const isSignedIn = !!authClient.useSession().data?.session const { selectedRef, gitContext } = usePostMetadata() const currentSha = gitContext?.sha ?? null @@ -85,24 +73,12 @@ export function CommentThreadClient({ return ( { - if (isSignedIn) { - setReplyingToId(null) - } - }} - onReply={(commentId) => { - if (isSignedIn) { - setReplyingToId(commentId) - } - }} owner={owner} reactions={reactions} - replyingToId={replyingToId} repo={repo} rootCommentId={rootCommentId} /> diff --git a/apps/web/app/[owner]/[repo]/[postNumber]/comment-thread.tsx b/apps/web/app/[owner]/[repo]/[postNumber]/comment-thread.tsx index 779e0fb..fcc1dd2 100644 --- a/apps/web/app/[owner]/[repo]/[postNumber]/comment-thread.tsx +++ b/apps/web/app/[owner]/[repo]/[postNumber]/comment-thread.tsx @@ -3,7 +3,6 @@ import Link from "next/link" import { useParams } from "next/navigation" import { Suspense } from "react" import type { AgentUIMessage } from "@/agent/types" -import type { ComposerProps } from "@/components/composer" import { CopyLinkButton } from "@/components/copy-link-button" import { CopyMarkdownButton } from "@/components/copy-markdown-button" import { DeleteCommentButton } from "@/components/delete-comment-button" @@ -15,10 +14,8 @@ import type { mentions as mentionsSchema, reactions as reactionsSchema, } from "@/lib/db/schema" -import { cn } from "@/lib/utils" import { CommentContent } from "./comment-content" import { MentionBanner } from "./mention-banner" -import { PostComposer } from "./post-composer" import { StreamingBadge, StreamingCommentProvider, @@ -36,8 +33,6 @@ export type AuthorInfo = { isLlm: boolean } -const REPLIES_ENABLED = false - function CommentItem({ owner, repo, @@ -46,13 +41,6 @@ function CommentItem({ isRootComment, author, commentNumber, - depth = 0, - children, - hasReplies, - onReply, - onCancelReply, - isReplying, - askingOptions, }: { owner: string repo: string @@ -62,20 +50,11 @@ function CommentItem({ isRootComment: boolean author: AuthorInfo commentNumber: string - depth?: number - children?: React.ReactNode - hasReplies?: boolean - onReply?: (commentId: string) => void - onCancelReply?: () => void - isReplying?: boolean - askingOptions: ComposerProps["options"]["asking"] }) { const profileUrl = author.isLlm ? `/llm/${author.username}` : `/user/${author.username}` - const canReply = REPLIES_ENABLED && depth === 0 && !isRootComment && onReply - const { postNumber } = useParams<{ postNumber: string }>() const actionLabel = isRootComment ? "posted" : "commented" @@ -83,12 +62,7 @@ function CommentItem({ const createdByLabel = comment.createdBy === "mcp" ? "via MCP" : "" const header = ( -
+
- - {hasReplies && ( -
-
- REPLY IN THREAD -
-
- )} - - {children && ( -
{children}
- )} - - {canReply ? ( - isReplying ? ( - askingOptions ? ( -
- -
- ) : null - ) : ( -
- -
- ) - ) : null}
) } @@ -231,10 +164,6 @@ export function CommentThread({ reactions, rootCommentId, commentNumbers, - replyingToId, - onReply, - onCancelReply, - askingOptions, }: { owner: string repo: string @@ -244,10 +173,6 @@ export function CommentThread({ reactions: Reaction[] rootCommentId: string | null commentNumbers: Map - replyingToId?: string | null - onReply?: (commentId: string) => void - onCancelReply?: () => void - askingOptions: ComposerProps["options"]["asking"] }) { const reactionsByComment: Record = {} for (const reaction of reactions) { @@ -257,10 +182,8 @@ export function CommentThread({ reactionsByComment[reaction.commentId].push(reaction) } - const topLevelComments = comments.filter((c) => c.threadCommentId === null) - const timeline: TimelineItem[] = [ - ...topLevelComments.map( + ...comments.map( (c) => ({ type: "comment", data: c, createdAt: c.createdAt }) as const ), ...mentions.map( @@ -268,15 +191,6 @@ export function CommentThread({ ), ].sort((a, b) => a.createdAt - b.createdAt) - const repliesByThread = new Map() - for (const c of comments) { - if (c.threadCommentId) { - const existing = repliesByThread.get(c.threadCommentId) ?? [] - existing.push(c) - repliesByThread.set(c.threadCommentId, existing) - } - } - return (
{timeline.map((item) => { @@ -296,54 +210,18 @@ export function CommentThread({ } const commentNumber = commentNumbers.get(comment.id) ?? "?" const isRootComment = comment.id === rootCommentId - const replies = repliesByThread.get(comment.id) ?? [] - const hasReplies = replies.length > 0 - return ( - {hasReplies && ( -
- {replies.map((reply) => { - const replyAuthor = authorsById[reply.authorId] - if (!replyAuthor) { - return null - } - const replyNumber = commentNumbers.get(reply.id) ?? "?" - return ( - - ) - })} -
- )} -
+ /> ) })}
diff --git a/apps/web/app/[owner]/[repo]/[postNumber]/page.tsx b/apps/web/app/[owner]/[repo]/[postNumber]/page.tsx index a998f1f..7495c9a 100644 --- a/apps/web/app/[owner]/[repo]/[postNumber]/page.tsx +++ b/apps/web/app/[owner]/[repo]/[postNumber]/page.tsx @@ -380,7 +380,6 @@ export default async function PostPage({
{ + test("numbers comments flat, ignoring thread metadata", () => { + const numbers = computeCommentNumbers([ + { id: "root", threadCommentId: null, createdAt: 100 }, + { id: "comment", threadCommentId: null, createdAt: 200 }, + { id: "reply", threadCommentId: "comment", createdAt: 201 }, + { id: "next", threadCommentId: null, createdAt: 300 }, + ]) + + expect(numbers.get("root")).toBe("1") + expect(numbers.get("comment")).toBe("2") + expect(numbers.get("reply")).toBe("3") + expect(numbers.get("next")).toBe("4") + }) +}) diff --git a/apps/web/lib/utils/comment-numbers.ts b/apps/web/lib/utils/comment-numbers.ts index 216500d..9192d0f 100644 --- a/apps/web/lib/utils/comment-numbers.ts +++ b/apps/web/lib/utils/comment-numbers.ts @@ -5,10 +5,10 @@ type Comment = { } /** - * Computes hierarchical comment numbers from a flat list of comments. + * Computes flat comment numbers from a list of comments. * - * Top-level comments: 1, 2, 3, 4... - * Replies in a thread: 3.1, 3.2, 3.3... + * Thread metadata is intentionally ignored while threaded replies are dormant, + * so every visible comment gets a top-level number: 1, 2, 3, 4... * * Numbers are deterministic based on createdAt order (with id as tiebreaker). */ @@ -23,18 +23,9 @@ export function computeCommentNumbers( }) const result = new Map() - const childCounters = new Map() - for (const comment of sorted) { - const threadNumber = comment.threadCommentId - ? result.get(comment.threadCommentId) - : null - - const counter = (childCounters.get(comment.threadCommentId) ?? 0) + 1 - childCounters.set(comment.threadCommentId, counter) - - const number = threadNumber ? `${threadNumber}.${counter}` : String(counter) - result.set(comment.id, number) + for (const [index, comment] of sorted.entries()) { + result.set(comment.id, String(index + 1)) } return result