Skip to content

fix(frontend): rewrite BeautifiedJsonView as collapsible tree#4343

Merged
junaway merged 15 commits into
release/v0.100.0from
fix/beautified-json-tree-view
May 19, 2026
Merged

fix(frontend): rewrite BeautifiedJsonView as collapsible tree#4343
junaway merged 15 commits into
release/v0.100.0from
fix/beautified-json-tree-view

Conversation

@mmabrouk
Copy link
Copy Markdown
Member

@mmabrouk mmabrouk commented May 15, 2026

Summary

Rewrites the BeautifiedJsonView component from a flat key-value list into a recursive, collapsible tree.

Multiple changes:

  • We don't automatically rename keys (removing _ and uppercasing)
  • We allow collapsing. Per default we expand to depth 2 + show ag.data expanded maximally
  • We allow copying values
  • Improved the way we visualize the hierarchy by adding vertical lines

What changed

  • Recursive tree layout. Objects and arrays render as collapsible nodes. Each level is indented with visible indent guides so users can trace nesting at a glance.
  • Type-colored scalar values. Strings, numbers, booleans, and null each get a distinct color. This makes it easy to scan a large payload and spot the value type you are looking for.
  • Shallow chat detection. Chat messages are still detected and rendered with role badges, but the detection is shallow (direct array, single message object, one-level known-key lookup, OpenAI choices format). It no longer digs through inputs/outputs/data wrappers, so the surrounding structure stays visible.
  • Hover-to-copy on every node. A copy button appears on hover for any row. It copies the serialized value of that node to the clipboard.
  • Collapse/expand all. A header toggle collapses or expands every node in one click. Individual nodes can also be toggled independently.

Test plan

  • Open the trace drawer for a span with nested JSON inputs/outputs. Verify the tree renders with correct indentation and collapsible nodes.
  • Click "Collapse all" and "Expand all". Verify all nodes respond.
  • Hover over a scalar value row and click the copy button. Paste into a text editor to confirm the value was copied.
  • Open a span whose output is an OpenAI-style {choices: [{message: {role: "assistant", content: "..."}}]} payload. Verify it renders as a chat message with a role badge.
  • Open a span with a single message object (e.g. {role: "user", content: "hello"}). Verify it renders as a chat message.
  • Open a span with a flat object (no chat structure). Verify it renders as a plain tree with no chat badges.
  • Tab through the component with keyboard only. Verify focus rings appear on interactive elements.

Demo Before and After

demo-beautify.mp4

…cessibility

Replace the flat field-per-key layout with a recursive tree renderer that
supports collapse/expand, indent guides, type-colored scalars, hover-to-copy,
and shallow chat detection. Fix hierarchy-collapsing bug caused by deep
extractChatMessages search, while preserving OpenAI choices format and
sender/author role alias detection from the old version.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment May 19, 2026 5:38pm

Request Review

@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. Frontend labels May 15, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fa0819d0-2f55-49a5-aff2-9d70c3ab490f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

BeautifiedJsonView is refactored into a component-driven, collapsible row tree: chat-detection helpers extract messages, simplifyValue centralizes AI envelope and metadata cleanup, new UI primitives (ScalarValue, CopyButton, NodeRow, TruncatedMessageBody, MessageNodeRow) render interactive rows, and RecursiveNode performs depth-limited recursive rendering; TraceSpanDrillInView resets viewMode when available modes change.

Changes

BeautifiedJsonView Row-Based Rendering Refactor

Layer / File(s) Summary
Chat Detection Utilities and Imports
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
React imports expanded with state/hooks; cell-renderer import switched to isChatMessagesArray; added CHAT_ARRAY_KEYS, isSingleMessage, and shallowExtractChatMessages to extract chat arrays, single-message objects, and OpenAI choices envelopes.
Value Simplification and Metadata Processing
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
simplifyValue unwraps AI SDK envelopes ({type:"text"}, {type:"tool-call"}, {type:"tool-result"}), simplifies single-element arrays, joins string-only arrays, and strips configured noise keys from objects; defines EDITOR_RESET_CLASSES and isShortLeaf.
Value-to-String and Render Removal
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
Removed legacy RenderedChatMessages usage and retained valueToString for non-collapsible leaf formatting and copying.
Scalar Value and Copy-to-Clipboard Components
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
ScalarValue renders short primitive leaves; CopyButton implements clipboard copy with transient “Copied” state and timer cleanup.
Interactive Row Layout Components
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
NodeRow provides collapsible rows with chevron and keyboard toggle, optional inline/meta rendering and conditional copy UI; TruncatedMessageBody clamps editor-backed markdown with overflow detection and show more/less controls.
Message Node Row
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
MessageNodeRow renders chat messages with role-based styling using TruncatedMessageBody inside a NodeRow and exposes copyable text.
Recursive Tree Rendering Engine
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
RecursiveNode recursively renders simplified values, performs shallow chat extraction (including envelope sibling-key handling), renders inline leaves or editor-backed strings, and expands object/array children with configurable depth limits.
BeautifiedJsonView Top-Level Component
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
Top-level logic computes simplified root, extracts and renders chat messages when present (handling envelope-key cases and rendering sibling keys), computes agDataExpandKeys for AG-specific nested expansion, and falls back to RecursiveNode for other roots.

TraceSpan viewMode reinitialization

Layer / File(s) Summary
Reset viewMode when availableViewModes change
web/oss/src/components/DrillInView/TraceSpanDrillInView.tsx
Adds derived viewModeKey and a useEffect to call setViewMode(getDefaultJsonViewMode(availableViewModes)) when the available view modes set changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately summarizes the main change: rewriting BeautifiedJsonView as a collapsible tree. It is concise, specific, and clearly conveys the primary objective.
Description check ✅ Passed The pull request description is comprehensive and directly related to the changeset. It details the refactoring objectives, key improvements, implementation details, and includes a test plan with specific verification steps.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/beautified-json-tree-view

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/oss/src/components/DrillInView/BeautifiedJsonView.tsx (1)

174-185: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

All-noise metadata objects still leak through simplification.

The noiseKeys.length < keys.length guard only cleans mixed objects. An object made entirely of METADATA_NOISE_KEYS comes back unchanged, so the metadata-stripping path misses the noisiest case.

🧹 Minimal fix
-        if (noiseKeys.length > 0 && noiseKeys.length < keys.length) {
+        if (noiseKeys.length > 0) {
             const cleaned: Record<string, unknown> = {}
             for (const k of keys) {
                 if (!METADATA_NOISE_KEYS.has(k)) {
                     cleaned[k] = rec[k]
                 }
             }
             return cleaned
         }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fc10ea21-010e-404f-9478-32a72bc9b09d

📥 Commits

Reviewing files that changed from the base of the PR and between 75dc5e2 and d15361e.

📒 Files selected for processing (1)
  • web/oss/src/components/DrillInView/BeautifiedJsonView.tsx

Comment thread web/oss/src/components/DrillInView/BeautifiedJsonView.tsx
Comment thread web/oss/src/components/DrillInView/BeautifiedJsonView.tsx Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 15, 2026

Railway Preview Environment

Status Destroyed (PR closed)

Updated at 2026-05-19T17:50:10.415Z

- Preserve sibling fields when extracting chat from wrapper objects
  (e.g. {messages: [...], usage, model} now shows usage and model
  alongside the chat, not just the messages)
- Fix metadata noise guard to also clean all-noise objects
- Use async/await for clipboard instead of .then() chains
- Initialize timer ref with null for React 19 compatibility
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels May 15, 2026
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. size:XL This PR changes 500-999 lines, ignoring generated files. labels May 15, 2026
@mmabrouk mmabrouk force-pushed the fix/beautified-json-tree-view branch 2 times, most recently from 478e43c to 5ada416 Compare May 15, 2026 19:45
@dosubot dosubot Bot removed the size:XXL This PR changes 1000+ lines, ignoring generated files. label May 15, 2026
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label May 15, 2026
…vigation

useState initializer only runs on mount — navigating from a text-only
parent span to a child span with structured messages kept the stale
"text" mode instead of defaulting to "beautified-json".
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 189948f5-b89d-4123-bcab-be40175314ba

📥 Commits

Reviewing files that changed from the base of the PR and between 87d4bb3 and c22edf1.

📒 Files selected for processing (1)
  • web/oss/src/components/DrillInView/TraceSpanDrillInView.tsx

Comment thread web/oss/src/components/DrillInView/TraceSpanDrillInView.tsx
@mmabrouk mmabrouk marked this pull request as draft May 18, 2026 18:06
…gation

EditorProvider uses initialValue which only sets content on mount.
When navigating between spans, the Lexical editor kept stale content
from the previous span. Adding key={text} forces a remount when the
underlying text changes.
…tree

Tool messages (role=tool) often contain JSON responses from function
calls. Instead of showing raw JSON text in the editor, parse the content
and render it as a RecursiveNode tree with the same collapse/expand and
copy behavior as tool call arguments.
@mmabrouk mmabrouk marked this pull request as ready for review May 18, 2026 18:41
@mmabrouk mmabrouk marked this pull request as ready for review May 18, 2026 19:06
@mmabrouk mmabrouk requested a review from ardaerzin May 18, 2026 19:06
Copy link
Copy Markdown
Contributor

@ardaerzin ardaerzin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with the changes, however would like us to consider making collapsible headers sticky so that in large data

  1. context is not lost
  2. folding can still happen without scrolling up

feat(frontend): add fade+pill truncation for long chat messages
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels May 19, 2026
Adds position:sticky to collapsible NodeRow headers so the innermost
visible parent stays pinned at the top of the scroll container. Child
headers naturally overlap parent headers, so only the deepest context
is shown at any scroll position.
Copy link
Copy Markdown
Contributor

@ardaerzin ardaerzin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @mmabrouk

@mmabrouk
Copy link
Copy Markdown
Member Author

@ardaerzin unfortunately that didn't work. I struggled implementing sticky headers. Can we postpone it to a follow-up PR?

@ardaerzin
Copy link
Copy Markdown
Contributor

@ardaerzin unfortunately that didn't work. I struggled implementing sticky headers. Can we postpone it to a follow-up PR?

@mmabrouk fair enough. I'll create a follow up ticket and assign it to @ashrafchowdury

@junaway junaway changed the base branch from main to release/v0.100.0 May 19, 2026 17:36
@junaway junaway merged commit 18f70a2 into release/v0.100.0 May 19, 2026
26 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Frontend Improvement size:XXL This PR changes 1000+ lines, ignoring generated files. UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants