Repository navigation
JSON breadcrumbs for the response viewer (YK-724) - #653
Conversation
Show where the cursor sits inside a JSON response as a row of clickable crumbs above the body (e.g. `$ > sort > link > filter > "category.id" > 0`). Array indices are their own crumbs so a click can isolate a single element. Clicking a crumb writes the corresponding JSONPath into the filter box and applies it, so orientation and filtering are the same gesture. Keys that aren't bare identifiers use bracket-quote notation (`["category.id"]`), matching the JSONPath the filter already accepts. Implemented by walking the CodeMirror JSONC syntax tree from the cursor to the root; selection works in the read-only viewer, so the path updates live as you click around. The bar scrolls horizontally with arrows when the path is deeper than the pane is wide. Closes YK-724. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzhRSKbv99YXc6myv8PhyH
- Show the breadcrumb bar for any JSON response, not just once a cursor has landed, so it reads as a permanent part of the viewer. - Rename the leftmost crumb to "Root" and make clicking it reset to the whole response with the filter box closed, instead of applying `$` (which JSONPath wraps in an array) or opening an empty filter. - Hide the crumbs while a filter is applied, since the AppliedFilterBar already reports the active path and the crumbs would only stack a redundant bar. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzhRSKbv99YXc6myv8PhyH
A caret in a line's leading whitespace resolved to the enclosing object or array, which dropped the leaf key (or collapsed the path to the root). The first attempt at picking the nearest child by distance guessed wrong between adjacent keys. Instead, anchor a whitespace caret to the first non-whitespace token on its line. Yaak pretty-prints the response so each key and array element starts its own line, making that token the line's own member. The breadcrumb now tracks "the line I'm on" with no guessing, and the two distance heuristics are gone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzhRSKbv99YXc6myv8PhyH
|
Thanks for the PR. This appears to match Yaak's contribution policy and is awaiting review by @gschier. This only means the PR is in scope for review. It does not mean the change has been reviewed or accepted for merge. |
|
Working through this one still, but hoping to get it into the next release! I'm liking it so far. Will probably just make some UX tweaks and then merge it in, hopefully this week |
|
Thoughts on these changes? I wanted a way for it to not take up any more space than the current viewer. CleanShot.2026-09-16.at.9.57.04.PM.mp4 |
|
@gschier Even better, love it. I really like how it doesn't take space away from the editor |
|
| if (!update.selectionSet && !update.docChanged) return; | ||
| const pos = update.state.selection.main.head; | ||
| onUpdate({ segments: jsonPathSegmentsAt(update.state, pos) }); |
There was a problem hiding this comment.
Breadcrumbs persist across responses
When the user switches between two completed JSON responses, TextViewer preserves its breadcrumb state while the response-specific editor is remounted. This listener does not run when the new editor is created, so the new response continues to show the previous response's breadcrumb path until the user clicks in the editor. Clicking a stale crumb can then apply the old response's JSONPath to the current body. Initialize or reset the breadcrumb when the response editor changes.
| * value directly inside an `Array` its index. Collected deepest-first, reversed. | ||
| */ | ||
| export function jsonPathSegmentsAt(state: EditorState, pos: number): JsonPathSegment[] | null { | ||
| const tree = syntaxTree(state); |
There was a problem hiding this comment.
Partial trees produce wrong paths
Large response parsing is time-limited, but this reads the current syntax tree without ensuring parsing has reached the caret. A click in an unparsed section can therefore resolve to the root or an incorrect ancestor. The breadcrumb listener also does not refresh when background parsing advances, so the wrong path can remain visible until the user moves the caret again. Ensure parsing reaches the caret or recompute the breadcrumb when the syntax tree changes.
Summary
Adds a breadcrumb bar above the JSON response body that shows where the caret is inside a deeply nested response, and turns a click into a JSONPath filter. Addresses YK-724, greenlit by @gschier.
What it does
Root > sort > link > filter > "category.id" > 0. Array indices are their own crumbs.["category.id"]), matching what the JSONPath filter accepts.Rootresets to the whole response (clears the filter, leaves the box closed).How it works
The path is derived from the CodeMirror JSONC syntax tree by walking from the caret to the root. A caret in a line's leading whitespace is anchored to the first non-whitespace token on that line — since the response is pretty-printed, each key/element starts its own line, so this tracks "the line I'm on" without guessing between neighbours. No new dependencies.
Files
components/core/Editor/json/jsonPath.ts— path extraction + JSONPath serialization (unit-tested, 13 cases)components/core/Editor/json/breadcrumbExtension.ts— CodeMirror extension emitting the path on selection changecomponents/responseViewers/JsonBreadcrumbBar.tsx— the bar (horizontal scroll + arrows on overflow)components/responseViewers/TextViewer.tsx— wiringFor discussion (interaction / discoverability)
Submission
CONTRIBUTING.md.Explicit permission feedback item (required if not a bug fix):
https://yaak.app/feedback/posts/breadcrumbs-for-json-responses
Related
🤖 Generated with Claude Code
https://claude.ai/code/session_01RzhRSKbv99YXc6myv8PhyH