Skip to content

JSON breadcrumbs for the response viewer (YK-724) - #653

Merged
gschier merged 6 commits into
mountain-loop:mainfrom
vlad-solomon:feat/json-breadcrumbs
Sep 17, 2026
Merged

gschier merged 6 commits into
mountain-loop:mainfrom
vlad-solomon:feat/json-breadcrumbs

Conversation

@vlad-solomon

@vlad-solomon vlad-solomon commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

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

  • Always-on breadcrumb bar at the top of the JSON response body, e.g. Root > sort > link > filter > "category.id" > 0. Array indices are their own crumbs.
  • Tracks the caret by line. Click anywhere on a line — key, value, or its indentation — and the bar reflects that line's member. Selection works in the read-only viewer, so it updates live.
  • Click a crumb to filter. It writes the corresponding JSONPath into the filter box and applies it, so orienting and filtering are one gesture. Keys that aren't bare identifiers use bracket-quote notation (["category.id"]), matching what the JSONPath filter accepts.
  • Root resets to the whole response (clears the filter, leaves the box closed).
  • Hidden while a filter is applied, since the existing "Response filtered by …" bar already reports the active path.

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 change
  • components/responseViewers/JsonBreadcrumbBar.tsx — the bar (horizontal scroll + arrows on overflow)
  • components/responseViewers/TextViewer.tsx — wiring

For discussion (interaction / discoverability)

  • Placement: currently at the top of the JSON body pane (visually under the tab bar). Happy to move it into the shared tab-bar row if you'd prefer.
  • Discoverability / opt-out: always on for JSON right now. A planned follow-up adds a Response breadcrumbs toggle in Settings → Editor (under "Wrap editor lines"). Open to whether it should ship on by default.

Submission

  • This PR is a bug fix.
  • If this PR is not a bug fix, I linked the feedback item where @gschier explicitly gave me permission to work on it.
  • I have read and followed CONTRIBUTING.md.
  • I tested this change locally.
  • I added or updated tests, or tests are not reasonable for this change.
  • I added screenshots or recordings, or this change does not affect the UI.

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

vlad-solomon and others added 3 commits September 14, 2026 14:34
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
@vlad-solomon

Copy link
Copy Markdown
Contributor Author

Here are a few screenshots:

  1. The breadcrumb bar in the editor, reacting to the caret position
image
  1. By clicking any segment of the breadcrumb you filter down to it
image

@gschier
gschier marked this pull request as ready for review September 15, 2026 15:51
@github-actions

github-actions Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

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.

@github-actions github-actions Bot added contribution: missing template Community PR is missing enough of the pull request template to review. contribution: explicit permission Community PR links feedback where @gschier explicitly allowed the work. and removed contribution: missing template Community PR is missing enough of the pull request template to review. labels Sep 15, 2026
@github-actions
github-actions Bot requested a review from gschier September 15, 2026 18:31
@gschier

gschier commented Sep 16, 2026 •

Copy link
Copy Markdown
Member

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

@gschier

gschier commented Sep 17, 2026

Copy link
Copy Markdown
Member

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

@vlad-solomon

vlad-solomon commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor Author

@gschier Even better, love it. I really like how it doesn't take space away from the editor

@gschier

gschier commented Sep 17, 2026

Copy link
Copy Markdown
Member

@greptile-apps

@github-actions
github-actions Bot requested a review from gschier September 17, 2026 13:28
@greptile-apps

greptile-apps Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

The PR should not merge until breadcrumb state is refreshed when switching completed responses, preventing stale paths from filtering the newly selected body.

Findings

  1. P1 Breadcrumbs Persist Across Responses ▶
  2. P2 Partial Trees Produce Wrong Paths ▶

Summary

Adds caret-aware JSON breadcrumbs to response bodies and connects breadcrumb selection to the existing JSONPath filtering flow.

  • Derives object keys and array indices from CodeMirror's JSONC syntax tree.
  • Serializes breadcrumb prefixes into filter-compatible JSONPath expressions.
  • Adds a horizontally scrollable breadcrumb bar that is hidden while a filter is active.
  • The review identified stale breadcrumb state when switching completed responses and a large-document parsing reliability concern.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  C[Caret or selection update] --> T[Resolve JSONC syntax node]
  T --> S[Build key and index segments]
  S --> B[Render breadcrumb bar]
  B -->|Click crumb| P[Serialize JSONPath prefix]
  P --> F[Apply response filter]
  F --> V[Render filtered response]
Loading

Reviews (1) · Last reviewed commit: "Merge branch 'main' into feat/json-bread..."

Comment on lines +21 to +23
if (!update.selectionSet && !update.docChanged) return;
const pos = update.state.selection.main.head;
onUpdate({ segments: jsonPathSegmentsAt(update.state, pos) });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 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.

@gschier
gschier merged commit 6ed25b9 into mountain-loop:main Sep 17, 2026
1 check passed
@gschier gschier mentioned this pull request Sep 17, 2026
5 of 6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution: explicit permission Community PR links feedback where @gschier explicitly allowed the work.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants