Skip to content

Commit d8088f8

Browse files
committed
refactor(app): wire session message comments
1 parent d551446 commit d8088f8

1 file changed

Lines changed: 10 additions & 84 deletions

File tree

packages/app/src/pages/session/message-timeline.tsx

Lines changed: 10 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
import { For, createEffect, createMemo, on, onCleanup, onMount, Show, Index, type JSX, createSignal } from "solid-js"
1+
import { For, createEffect, createMemo, on, onCleanup, onMount, Show, type JSX, createSignal } from "solid-js"
22
import { createStore, produce } from "solid-js/store"
33
import { useNavigate } from "@solidjs/router"
44
import { useMutation } from "@tanstack/solid-query"
55
import { Button } from "@opencode-ai/ui/button"
6-
import { FileIcon } from "@opencode-ai/ui/file-icon"
76
import { Icon } from "@opencode-ai/ui/icon"
87
import { IconButton } from "@opencode-ai/ui/icon-button"
98
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
109
import { Dialog } from "@opencode-ai/ui/dialog"
1110
import { Spinner } from "@opencode-ai/ui/spinner"
1211
import { SessionTurn } from "@opencode-ai/ui/session-turn"
1312
import { ScrollView } from "@opencode-ai/ui/scroll-view"
14-
import type { AssistantMessage, Message as MessageType, Part, TextPart, UserMessage } from "@opencode-ai/sdk/v2"
13+
import type { AssistantMessage, Message as MessageType, Part, UserMessage } from "@opencode-ai/sdk/v2"
1514
import { showToast } from "@opencode-ai/ui/toast"
1615
import { Binary } from "@opencode-ai/util/binary"
17-
import { getFilename } from "@opencode-ai/util/path"
1816
import { collectTimelineScrollMetrics } from "@/pages/session/session-timeline-scroll-anchors"
1917
import {
2018
type TimelineScrollControllerResult,
@@ -29,6 +27,11 @@ import {
2927
shouldMarkTimelineBoundaryGesture,
3028
} from "@/pages/session/session-timeline-scroll-intents"
3129
import { createTimelineStaging } from "@/pages/session/session-timeline-staging"
30+
import {
31+
areMessageCommentsEqual,
32+
extractMessageComments,
33+
SessionMessageComments,
34+
} from "@/pages/session/session-message-comments"
3235
import { taskDescription } from "@/pages/session/task-description"
3336
import { buildTurnMessagesByUserID, emptyAssistantMessages } from "@/pages/session/session-messages"
3437
import {
@@ -51,19 +54,9 @@ import { useShellSurface } from "@/context/shell-surface"
5154
import { useSync } from "@/context/sync"
5255
import { messageAgentColor } from "@/utils/agent"
5356
import { sessionTitle } from "@/utils/session-title"
54-
import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note"
5557
import { makeTimer } from "@solid-primitives/timer"
5658
import { webSearchRecoveryToast } from "./websearch-toasts"
5759

58-
type MessageComment = {
59-
path: string
60-
comment: string
61-
selection?: {
62-
startLine: number
63-
endLine: number
64-
}
65-
}
66-
6760
function isWebSearchToolPart(part: Part): part is Extract<Part, { type: "tool" }> {
6861
return part.type === "tool" && part.tool === "websearch"
6962
}
@@ -103,25 +96,6 @@ type TurnChangeDisplay = {
10396
}>
10497
}
10598

106-
const messageComments = (parts: Part[]): MessageComment[] =>
107-
parts.flatMap((part) => {
108-
if (part.type !== "text" || !(part as TextPart).synthetic) return []
109-
const next = readCommentMetadata(part.metadata) ?? parseCommentNote(part.text)
110-
if (!next) return []
111-
return [
112-
{
113-
path: next.path,
114-
comment: next.comment,
115-
selection: next.selection
116-
? {
117-
startLine: next.selection.startLine,
118-
endLine: next.selection.endLine,
119-
}
120-
: undefined,
121-
},
122-
]
123-
})
124-
12599
export { taskDescription }
126100

127101
export function MessageTimeline(props: {
@@ -929,18 +903,9 @@ export function MessageTimeline(props: {
929903
{(messageID, index) => {
930904
const userMessage = createMemo(() => props.renderedUserMessages[index()])
931905
const active = createMemo(() => activeMessageID() === messageID)
932-
const comments = createMemo(() => messageComments(sync.data.part[messageID] ?? []), [], {
933-
equals: (a, b) =>
934-
a.length === b.length &&
935-
a.every(
936-
(c, i) =>
937-
c.path === b[i].path &&
938-
c.comment === b[i].comment &&
939-
c.selection?.startLine === b[i].selection?.startLine &&
940-
c.selection?.endLine === b[i].selection?.endLine,
941-
),
906+
const comments = createMemo(() => extractMessageComments(sync.data.part[messageID] ?? []), [], {
907+
equals: areMessageCommentsEqual,
942908
})
943-
const commentCount = createMemo(() => comments().length)
944909
return (
945910
<div
946911
id={props.anchor(messageID)}
@@ -954,46 +919,7 @@ export function MessageTimeline(props: {
954919
"contain-intrinsic-size": active() ? undefined : "auto 500px",
955920
}}
956921
>
957-
<Show when={commentCount() > 0}>
958-
<div class="w-full px-4 md:px-5 pb-2">
959-
<div class="ml-auto max-w-[82%] overflow-x-auto no-scrollbar">
960-
<div class="flex w-max min-w-full justify-end gap-2">
961-
<Index each={comments()}>
962-
{(commentAccessor: () => MessageComment) => {
963-
const comment = createMemo(() => commentAccessor())
964-
return (
965-
<Show when={comment()}>
966-
{(c) => (
967-
<div class="shrink-0 max-w-[260px] rounded-[6px] border border-border-weak bg-bg-base px-2.5 py-2">
968-
<div class="flex items-center gap-1.5 min-w-0 text-h3 text-fg-strong">
969-
<FileIcon
970-
node={{ path: c().path, type: "file" }}
971-
class="size-3.5 shrink-0"
972-
/>
973-
<span class="truncate">{getFilename(c().path)}</span>
974-
<Show when={c().selection}>
975-
{(selection) => (
976-
<span class="shrink-0 text-fg-weak">
977-
{selection().startLine === selection().endLine
978-
? `:${selection().startLine}`
979-
: `:${selection().startLine}-${selection().endLine}`}
980-
</span>
981-
)}
982-
</Show>
983-
</div>
984-
<div class="pt-1 text-body text-fg-strong whitespace-pre-wrap break-words">
985-
{c().comment}
986-
</div>
987-
</div>
988-
)}
989-
</Show>
990-
)
991-
}}
992-
</Index>
993-
</div>
994-
</div>
995-
</div>
996-
</Show>
922+
<SessionMessageComments comments={comments()} />
997923
<SessionTurn
998924
sessionID={sessionID() ?? ""}
999925
messageID={messageID}

0 commit comments

Comments
 (0)