From 45763e1e098e01b4bbde339d761e2a13cd1d951f Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Wed, 16 Sep 2026 00:48:18 +0900 Subject: [PATCH] web: use hydrated commit list Signed-off-by: Seongmin Lee --- web/src/fixtures/pull.ts | 7 +----- web/src/lib/api/comment.ts | 3 ++- .../lib/components/comment/comments.test.ts | 6 +---- web/src/lib/components/comment/comments.ts | 23 +++++++++++++------ .../repo/pulls/PullDiscussion.stories.svelte | 4 ++-- .../repo/pulls/PullReviewComment.svelte | 3 +-- .../[handle]/[repo]/pulls/[aturi]/+layout.ts | 6 ++--- .../[version]/[[range]]/PullViewPage.svelte | 14 ++++------- 8 files changed, 31 insertions(+), 35 deletions(-) diff --git a/web/src/fixtures/pull.ts b/web/src/fixtures/pull.ts index 201834181..d22284cc0 100644 --- a/web/src/fixtures/pull.ts +++ b/web/src/fixtures/pull.ts @@ -65,12 +65,7 @@ export const pullHead = pullVersions[pullVersions.length - 1]!.head; const commentUri = (rkey: string, did: string) => `at://${did}/sh.tangled.feed.comment/${rkey}`; -const pinned = (oid: string) => - ({ - $type: "sh.tangled.embed.commit", - repo: sourceRepoDid, - commit: { $type: "sh.tangled.git.oid", oid } - }) as CommentView["embed"]; +const pinned = (oid: string) => ({ repo: sourceRepoDid, commit: oid }) as CommentView["embed"]; // two loose comments and two pinned to a commit, spread across the versions so // the discussion shows its version headers and the range filter has something diff --git a/web/src/lib/api/comment.ts b/web/src/lib/api/comment.ts index 750af8a7f..0d84ce6f4 100644 --- a/web/src/lib/api/comment.ts +++ b/web/src/lib/api/comment.ts @@ -5,6 +5,7 @@ import { jsonGet } from "$lib/api/_request"; import type { RecordView } from "$lib/api/records"; import { deleteRecord, putRecord } from "$lib/api/write"; import type * as ShTangledFeedComment from "$lib/api/lexicons/types/sh/tangled/feed/comment"; +import type * as ShTangledFeedDefs from "$lib/api/lexicons/types/sh/tangled/feed/defs"; export type CommentRecord = ShTangledFeedComment.Main; @@ -30,7 +31,7 @@ export const deleteComment = async ( export interface CommentListPage { cursor?: string | null; - items: RecordView[]; + items: ShTangledFeedDefs.CommentView[]; } export const listComments = ( diff --git a/web/src/lib/components/comment/comments.test.ts b/web/src/lib/components/comment/comments.test.ts index 8dfd91144..6f23d3df4 100644 --- a/web/src/lib/components/comment/comments.test.ts +++ b/web/src/lib/components/comment/comments.test.ts @@ -76,11 +76,7 @@ describe("groupCommentsByVersion", () => { const pinned = (rkey: string, oid: string): CommentView => ({ ...comment(rkey, "2026-01-02T00:00:00Z"), - embed: { - $type: "sh.tangled.embed.commit", - repo: "did:plc:alice", - commit: { $type: "sh.tangled.git.oid", oid } - } + embed: { repo: "did:plc:alice", commit: oid } }); describe("countCommentsByCommit", () => { diff --git a/web/src/lib/components/comment/comments.ts b/web/src/lib/components/comment/comments.ts index dbd5ee42c..1916c0bec 100644 --- a/web/src/lib/components/comment/comments.ts +++ b/web/src/lib/components/comment/comments.ts @@ -1,5 +1,6 @@ import type { BobbinContext } from "$lib/api/client"; import type { CommentListPage, CommentRecord } from "$lib/api/comment"; +import type * as ShTangledEmbedCommit from "$lib/api/lexicons/types/sh/tangled/embed/commit"; import { COMMENT_AUTHOR_DOCS } from "$lib/api/descriptors"; import { authorOf, enrich, target, type Sidecar } from "$lib/api/enrich"; import { INVALID_HANDLE } from "$lib/api/identity"; @@ -21,7 +22,7 @@ export interface CommentView { body: string; bodyHtml: string | null; // carried so an edit rewrites the record without dropping what it pinned - embed?: CommentRecord["embed"]; + embed?: ShTangledEmbedCommit.View; reactions?: ReactionGroup[]; deleted?: boolean; } @@ -118,11 +119,19 @@ export function groupCommentsByVersion( return groups.filter((group) => group.version !== undefined || group.comments.length); } +// the view hands back a bare oid; a rewrite has to pin the record shape again +export const commitEmbedRecord = (embed: CommentView["embed"]): CommentRecord["embed"] => + embed && { + $type: "sh.tangled.embed.commit", + repo: embed.repo, + commit: { $type: "sh.tangled.git.oid", oid: embed.commit } + }; + export function countCommentsByCommit(comments: CommentView[]): Map { const counts = new Map(); for (const { embed } of comments) { if (!embed) continue; - const oid = embed.commit.oid; + const oid = embed.commit; counts.set(oid, (counts.get(oid) ?? 0) + 1); } return counts; @@ -136,7 +145,7 @@ export function filterCommentsByCommit( if (!filter) return comments; return comments.filter((comment) => { // full oids on both sides, so equality is enough -- no prefix matching - const oid = comment.embed?.commit.oid; + const oid = comment.embed?.commit; if (!oid) return true; const commit = commits.find((c) => c.hash === oid); return !!commit && filter(commit); @@ -152,7 +161,7 @@ export const toThreadInputs = async ( Promise.all( items.map(async (item): Promise => { const author = authorOf(docs, item.uri, COMMENT_AUTHOR_DOCS); - const body = item.value.body?.text ?? ""; + const body = item.body?.text ?? ""; return { comment: { uri: item.uri, @@ -160,13 +169,13 @@ export const toThreadInputs = async ( rkey: rkeyFromUri(item.uri), authorDid: author.did, authorHandle: author.handle ?? INVALID_HANDLE, - createdAt: item.value.createdAt, + createdAt: item.createdAt, body, bodyHtml: body ? await orNull(renderMarkup(body, markupCtx)) : null, ...extra?.(item.uri) }, - replyTo: item.value.replyTo?.uri ?? null, - replyToCid: item.value.replyTo?.cid + replyTo: item.replyTo?.uri ?? null, + replyToCid: item.replyTo?.cid }; }) ); diff --git a/web/src/lib/components/repo/pulls/PullDiscussion.stories.svelte b/web/src/lib/components/repo/pulls/PullDiscussion.stories.svelte index bb4c3758e..e12ec8f8d 100644 --- a/web/src/lib/components/repo/pulls/PullDiscussion.stories.svelte +++ b/web/src/lib/components/repo/pulls/PullDiscussion.stories.svelte @@ -4,7 +4,7 @@ import PullDiscussion from "$lib/components/repo/pulls/PullDiscussion.svelte"; import { sampleComments, sampleMarkup } from "$fixtures/comments"; import { pipelinesByCommitHash } from "$fixtures/pipelines"; - import type { CommentRecord } from "$lib/api/comment"; + import type { CommentView } from "$lib/components/comment/comments"; import type { CommitSummary } from "$lib/components/repo/types"; type Props = ComponentProps; @@ -41,7 +41,7 @@ createdAt: "2024-10-04T11:00:00Z", body: "This line needs a null check before the merge.", bodyHtml: "

This line needs a null check before the merge.

", - embed: { commit: { oid: commits[0].hash } } as CommentRecord["embed"] + embed: { commit: commits[0].hash } as CommentView["embed"] }; // two versions straddling the sample comments (2024-10-02 through 2024-11-10), diff --git a/web/src/lib/components/repo/pulls/PullReviewComment.svelte b/web/src/lib/components/repo/pulls/PullReviewComment.svelte index e4134eefe..e0e3488fd 100644 --- a/web/src/lib/components/repo/pulls/PullReviewComment.svelte +++ b/web/src/lib/components/repo/pulls/PullReviewComment.svelte @@ -76,8 +76,7 @@
{#if comment.embed} - {comment.embed.commit.oid.slice(0, 8)} + {comment.embed.commit.slice(0, 8)} {/if} {#if editing} { const comments = await Promise.all( (page?.output.items ?? []).map(async (item): Promise => { const author = authorOf(page?.data ?? {}, item.uri, COMMENT_AUTHOR_DOCS); - const body = item.value.body?.text ?? ""; + const body = item.body?.text ?? ""; return { uri: item.uri, cid: item.cid, rkey: rkeyFromUri(item.uri), authorDid: author.did, authorHandle: author.handle, - createdAt: item.value.createdAt, - embed: item.value.embed, + createdAt: item.createdAt, + embed: item.embed, body, bodyHtml: body ? await renderMarkup(body, markup).catch(() => null) : null }; diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.svelte b/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.svelte index 7db91f003..dabaaff16 100644 --- a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.svelte +++ b/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.svelte @@ -50,7 +50,7 @@ import type { ResolvedPathname } from "$app/types"; import type { Did } from "@atcute/lexicons/syntax"; import type { PullState } from "$lib/api/records"; - import type { CommentView } from "$lib/components/comment/comments"; + import { commitEmbedRecord, type CommentView } from "$lib/components/comment/comments"; import Button from "$lib/components/ui/Button.svelte"; import Spinner from "$lib/components/ui/Spinner.svelte"; import ErrorAlert from "$lib/components/ui/Error.svelte"; @@ -385,18 +385,14 @@ if (!agent || !user) return; const rkey = tidNow(); const createdAt = new Date().toISOString(); - const embed: CommentRecord["embed"] = commit - ? { - $type: "sh.tangled.embed.commit", - repo: data.sourceRepoDid as Did, - commit: { $type: "sh.tangled.git.oid", oid: commit } - } + const embed: CommentView["embed"] = commit + ? { repo: data.sourceRepoDid as Did, commit } : undefined; const saved = await putComment(agent, rkey, { $type: "sh.tangled.feed.comment", subject: { uri: data.uri, cid: pull.cid } as CommentRecord["subject"], body: { $type: "sh.tangled.markup.markdown", text: body }, - embed, + embed: commitEmbedRecord(embed), createdAt }); if (data.publicConfig?.bobbinUrl) { @@ -442,7 +438,7 @@ $type: "sh.tangled.feed.comment", subject: { uri: data.uri, cid: pull.cid } as CommentRecord["subject"], body: { $type: "sh.tangled.markup.markdown", text: edited.body }, - embed: edited.embed, + embed: commitEmbedRecord(edited.embed), createdAt: edited.createdAt }); if (data.publicConfig?.bobbinUrl) { -- 2.51.2