Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 103 additions & 25 deletions web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,108 @@ const NodeRow = memo(function NodeRow({
)
})

// ── TruncatedMessageBody ───────────────────────────────────────────────
//
// Wraps the editor for a chat message. When the content exceeds
// TRUNCATE_HEIGHT_PX the body is clamped with a bottom fade overlay and
// a centered "Show more" pill. Clicking the pill expands to full height
// and shows a "Show less" pill at the bottom.

const TRUNCATE_HEIGHT_PX = 160
const EXPAND_SENTINEL_PX = 9999

const PILL_BUTTON_CLASSES =
"text-[11px] font-medium text-[var(--ant-color-text-secondary)] bg-[var(--ant-color-fill-quaternary)] hover:bg-[var(--ant-color-fill-tertiary)] border border-solid border-[var(--ant-color-border-secondary)] rounded-full px-3 py-0.5 cursor-pointer focus-visible:ring-1 focus-visible:ring-[var(--ant-color-primary)] focus-visible:outline-none motion-safe:transition-colors"

const TruncatedMessageBody = memo(function TruncatedMessageBody({
editorId,
text,
}: {
editorId: string
text: string
}) {
const measureRef = useRef<HTMLDivElement>(null)
const [needsTruncation, setNeedsTruncation] = useState(false)
const [expanded, setExpanded] = useState(false)

useEffect(() => {
setExpanded(false)
const el = measureRef.current
if (!el) return
const check = () => setNeedsTruncation(el.scrollHeight > TRUNCATE_HEIGHT_PX + 8)
check()
const observer = new ResizeObserver(check)
observer.observe(el)
return () => observer.disconnect()
}, [text])

const toggle = useCallback(() => setExpanded((v) => !v), [])

const isTruncated = needsTruncation && !expanded

return (
<div className="relative">
<div
className="overflow-hidden motion-safe:transition-[max-height] motion-safe:duration-200"
style={{maxHeight: isTruncated ? TRUNCATE_HEIGHT_PX : EXPAND_SENTINEL_PX}}
>
<div ref={measureRef}>
<EditorProvider
id={editorId}
initialValue={text}
showToolbar={false}
enableTokens={false}
readOnly
className={EDITOR_RESET_CLASSES}
>
<MarkdownModeSync isMarkdownView={false} />
<EditorWrapper
initialValue={text}
disabled
showToolbar={false}
noProvider
readOnly
boundHeight={false}
/>
</EditorProvider>
</div>
</div>

{isTruncated ? (
<div className="absolute bottom-0 left-0 right-0 flex flex-col items-center">
<div
className="w-full h-10 bg-gradient-to-t from-[var(--ant-color-bg-container)] to-transparent pointer-events-none"
aria-hidden="true"
/>
<div className="w-full flex justify-center pb-1 bg-[var(--ant-color-bg-container)]">
<button
type="button"
onClick={toggle}
aria-expanded={false}
className={PILL_BUTTON_CLASSES}
>
Show more
</button>
</div>
</div>
) : null}

{needsTruncation && expanded ? (
<div className="flex justify-center pt-1 pb-0.5">
<button
type="button"
onClick={toggle}
aria-expanded={true}
className={PILL_BUTTON_CLASSES}
>
Show less
</button>
</div>
) : null}
</div>
)
})

// ── MessageNodeRow ──────────────────────────────────────────────────────

const MessageNodeRow = memo(function MessageNodeRow({
Expand All @@ -488,30 +590,6 @@ const MessageNodeRow = memo(function MessageNodeRow({
[msg.role, roleColor],
)

const body = useMemo(
() => (
<EditorProvider
id={editorId}
initialValue={text}
showToolbar={false}
enableTokens={false}
readOnly
className={EDITOR_RESET_CLASSES}
>
<MarkdownModeSync isMarkdownView={false} />
<EditorWrapper
initialValue={text}
disabled
showToolbar={false}
noProvider
readOnly
boundHeight={false}
/>
</EditorProvider>
),
[editorId, text],
)

return (
<NodeRow
keyLabel={label}
Expand All @@ -520,7 +598,7 @@ const MessageNodeRow = memo(function MessageNodeRow({
collapsible
defaultOpen
value={text}
body={body}
body={<TruncatedMessageBody editorId={editorId} text={text} />}
/>
)
})
Expand Down
Loading