Conversation
- Removed the search context and related logic from SpanItem -Uplifted a search functionality in SpanTree to filter spans based on the query - Updated rendering logic to display only matching spans in the tree
|
@betegon is attempting to deploy a commit to the Sentry Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
BYK
left a comment
There was a problem hiding this comment.
I think this is a pretty good start but I'm concerned about the efficiency.
I also would like to keep the "find & highlight" approach as @Shubhdeep12 mentioned too. Maybe we can add a toggle as he mentioned?
| const matchesQuery = (span: Span): boolean | undefined => { | ||
| return span.span_id.includes(query) || span.op?.includes(query) || span.description?.includes(query); | ||
| }; |
There was a problem hiding this comment.
| const matchesQuery = (span: Span): boolean | undefined => { | |
| return span.span_id.includes(query) || span.op?.includes(query) || span.description?.includes(query); | |
| }; | |
| const matchesQuery = (span: Span): boolean | undefined => (span.span_id.includes(query) || span.op?.includes(query) || span.description?.includes(query)); |
There was a problem hiding this comment.
I also wonder if we can make useSearch() return this matcher, wrapped in useCallback() or something to make things more efficient?
There was a problem hiding this comment.
Done! I also made sure that it returns a boolean:
const matchesQuery = useCallback(
(span: Span): boolean => {
const q = context.query.toLowerCase();
return (
(span.span_id.toLowerCase().includes(q) ||
span.op?.toLowerCase().includes(q) ||
span.description?.toLowerCase().includes(q)) ??
false
);
},
[context.query],
);P.S. I added case-insensitive matching. I believe it’s one of the first things anyone would expect from a search feature.
| const hasMatchingDescendant = (span: Span): boolean => { | ||
| if (matchesQuery(span)) return true; | ||
| if (!span.children) return false; | ||
| return span.children.some(hasMatchingDescendant); | ||
| }; |
There was a problem hiding this comment.
I feel like we may want to cache this or do a more efficient depth-first search as we'd be scanning down the same spans as we do deeper.
There was a problem hiding this comment.
Good call! I’ve memoized each of the spans we process now.
if (showOnlyMatched) {
const spanMemo = new Map<string, boolean>();
const hasMatchingDescendant = (span: Span): boolean => {
if (spanMemo.has(span.span_id)) return spanMemo.get(span.span_id)!;
const result = matchesQuery(span) || (span.children?.some(child => hasMatchingDescendant(child)) ?? false);
spanMemo.set(span.span_id, result);
return result;
};
return tree.filter(span => hasMatchingDescendant(span));
}
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #747 +/- ##
==========================================
- Coverage 33.03% 32.81% -0.22%
==========================================
Files 93 93
Lines 5788 5838 +50
Branches 118 118
==========================================
+ Hits 1912 1916 +4
- Misses 3876 3922 +46 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Thanks for the detailed feedback, @BYK I’ve implemented your suggestions, including:
I think we’re in a better spot now, happy to keep iterating if you have more suggestions 😉 Here’s a quick screenshot video showing how the toggle works. Screen.Recording.2025-04-06.at.19.47.50.mp4 |
| }`} | ||
| onClick={() => setShowOnlyMatched(!showOnlyMatched)} | ||
| > | ||
| Only Show Matches |
There was a problem hiding this comment.
I think it would be better to switch this into a checkbox and make the text shorter (or even use an icon with a very short label)
| return span.span_id.includes(query) || span.op?.includes(query) || span.description?.includes(query); | ||
| }, [query, span.span_id, span.op, span.description]); | ||
|
|
||
| const isQueried = !showOnlyMatched && query && matchesQuery(span); |
There was a problem hiding this comment.
I think renaming this to shouldHighlight makes more sense with the new approach.
| const isQueried = !showOnlyMatched && query && matchesQuery(span); | |
| const shouldHighlight = !showOnlyMatched && query && matchesQuery(span); |
| const { query, matchesQuery, showOnlyMatched } = useSearch(); | ||
|
|
||
| const filteredTree = useMemo(() => { | ||
| if (!query) return tree; |
There was a problem hiding this comment.
Early return here with showOnlyMatched would make it easier to follow.
| if (!query) return tree; | |
| if (!query || !showOnlyMatched) return tree; |
| const filteredTree = useMemo(() => { | ||
| if (!query) return tree; | ||
| if (showOnlyMatched) { | ||
| const spanMemo = new Map<string, boolean>(); |
There was a problem hiding this comment.
This implementation is not bad but I don't think the cache would be shared across children/siblings. I think this cache should be moved to useSearch() level and get reset when query changes.
| return tree; | ||
| }, [query, tree, showOnlyMatched, matchesQuery]); | ||
|
|
||
| if (!tree || !tree.length) return null; |
There was a problem hiding this comment.
Shouldn't we replace the tree here with filteredTree?
| if (!tree || !tree.length) return null; | |
| if (!filteredTree|| !tree.filteredTree) return null; |
| const q = context.query.toLowerCase(); | ||
| return ( | ||
| (span.span_id.toLowerCase().includes(q) || | ||
| span.op?.toLowerCase().includes(q) || | ||
| span.description?.toLowerCase().includes(q)) ?? | ||
| false |
There was a problem hiding this comment.
I think it would be more efficient if we create a:
const queryMatcher = new RegExp(RegExp.escape(query), 'i');and then do queryMatcher.test(span.op) etc. afterwards. You may need to polyfill RegExp.escape as it doesn't seem to have wide browser support without flags.
Finally, a bit of a nitpick, we may wanna limit matching to only when the query is more than 2 characters as I don't want to match on a or even ab probably.
packages/sidecar/src/contextlines.ts
Outdated
| @@ -1,8 +1,8 @@ | |||
| import { LEAST_UPPER_BOUND, TraceMap, originalPositionFor, sourceContentFor } from '@jridgewell/trace-mapping'; | |||
There was a problem hiding this comment.
Let's not change any other files outside of the context of this patch. I'll revert this for you.
BYK
left a comment
There was a problem hiding this comment.
I think we may wanna expand all trees when there's a query set and "only show matches" is selected as otherwise it gets a bit confusing when trying to figure out why a top-level span was not filtered (because it has some child matching the query but is collapsed so the child is not visible).
I also have all these notes but I think the PR is a net improvement so gonna approve, merge, and cut a new release and push the improvements to future releases.
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing). If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @spotlightjs/astro@3.2.0 ### Minor Changes - feat: Keep profile spans collapsed ([#737](#737)) ### Patch Changes - fix: Null-check sentryClient.\_options ([#736](#736)) - Updated dependencies \[[`3d569f30fb746d90ecabaac35d23d980360ea99c`](3d569f3), [`d3a2f0a0fae9074802b0551f3e1662833c1423c9`](d3a2f0a), [`d0315bc2ead9ccea722cc73c6b5fd7d9fed3f4a4`](d0315bc)]: - @spotlightjs/spotlight@2.13.0 ## @spotlightjs/electron@1.7.0 ### Minor Changes - feat: Keep profile spans collapsed ([#737](#737)) ### Patch Changes - fix: Null-check sentryClient.\_options ([#736](#736)) - Updated dependencies \[[`3d569f30fb746d90ecabaac35d23d980360ea99c`](3d569f3), [`7ea7de17b7ccf9f0c8edb8b413176d2f3482780c`](7ea7de1), [`263ba283efa247e05a022d7f1305cbf819e3e783`](263ba28), [`7ac9fd255cfe85d66e79d632e1d309c3e88d8092`](7ac9fd2), [`a76b2dadb28ce8699c80fc81b709050655bd4629`](a76b2da), [`d3a2f0a0fae9074802b0551f3e1662833c1423c9`](d3a2f0a), [`f2a48b05a41f80e08d1666247f7ccae60bc3d9e7`](f2a48b0), [`6d26f0d21b3ae75e3d81e48ceb2d8f727a94420f`](6d26f0d), [`a8f632357d9dcc46187b00724c14dd4423dfa467`](a8f6323), [`9888dbfc6778de910a2aeae9f3e86f0b2f716a18`](9888dbf), [`ced3e736dfef15d368cac202a10eec4eba7508be`](ced3e73)]: - @spotlightjs/overlay@2.14.0 - @spotlightjs/sidecar@1.11.3 ## @spotlightjs/overlay@2.14.0 ### Minor Changes - feat: Keep profile spans collapsed ([#737](#737)) - Swap "Errors" and "Explore" tab places, making "Explore" the default. It makes more sense this way as there is almost ([#758](#758)) guaranteed to have traces in a good setup but not really errors. - Restructured Sentry integration tabs and components ([#765](#765)) - - \#731: Search Bar sticky and fixed overflow across the overlay. ([#740](#740)) - Include filter functionality when searching spans ([#747](#747)) ### Patch Changes - Fixed parsing of envelope data. ([#751](#751)) - fix: Null-check sentryClient.\_options ([#736](#736)) - format node internals correctly in stacktrace ([#739](#739)) - Fixed #738 ([#741](#741)) ## @spotlightjs/spotlight@2.13.0 ### Minor Changes - feat: Keep profile spans collapsed ([#737](#737)) ### Patch Changes - fix: Null-check sentryClient.\_options ([#736](#736)) - Remove obsolete packages from dependencies ([#761](#761)) - Updated dependencies \[[`3d569f30fb746d90ecabaac35d23d980360ea99c`](3d569f3), [`7ea7de17b7ccf9f0c8edb8b413176d2f3482780c`](7ea7de1), [`263ba283efa247e05a022d7f1305cbf819e3e783`](263ba28), [`7ac9fd255cfe85d66e79d632e1d309c3e88d8092`](7ac9fd2), [`a76b2dadb28ce8699c80fc81b709050655bd4629`](a76b2da), [`d3a2f0a0fae9074802b0551f3e1662833c1423c9`](d3a2f0a), [`f2a48b05a41f80e08d1666247f7ccae60bc3d9e7`](f2a48b0), [`6d26f0d21b3ae75e3d81e48ceb2d8f727a94420f`](6d26f0d), [`a8f632357d9dcc46187b00724c14dd4423dfa467`](a8f6323), [`9888dbfc6778de910a2aeae9f3e86f0b2f716a18`](9888dbf), [`ced3e736dfef15d368cac202a10eec4eba7508be`](ced3e73)]: - @spotlightjs/overlay@2.14.0 - @spotlightjs/sidecar@1.11.3 ## @spotlightjs/sidecar@1.11.3 ### Patch Changes - use nanosecond timestamp for captured filenames ([#776](#776)) - Improve DX by always showing the Spotlight URL, even if the sidecar was already running. Makes it easy to cmd/ctrl+click ([#748](#748)) and open in browser. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Related to #731 >We should have an actual filtering functionality, not just highlight These changes add filtering to span search - uplifted search functionality from `SpanItem` to `SpanTree`. - Implemented DFS to handle nested search. - Also removed highlighting from matching spans. The results display not only the direct matches but also their hierarchical context up to the root: <img width="1422" alt="Screenshot 2025-03-24 at 22 24 09" src="https://github.com/user-attachments/assets/cdbccb82-64d0-4572-a2cb-238042681994" /> <img width="1428" alt="Screenshot 2025-03-24 at 22 24 31" src="https://github.com/user-attachments/assets/beed8e93-3c46-4375-8094-6c885c4a8794" /> <img width="1425" alt="Screenshot 2025-03-24 at 22 23 58" src="https://github.com/user-attachments/assets/824fec08-5c2c-4d7b-be79-495df05dea79" /> Since spans are time-sorted, it would be useful to add a feature like `+<#items>` between results. This would allow you to jump directly to the result you’re looking for when debugging. I’ve been using Spotlight for the past few days, and this addition would have been very helpful.  --------- Co-authored-by: Burak Yigit Kaya <byk@sentry.io>
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing). If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @spotlightjs/astro@3.2.0 ### Minor Changes - feat: Keep profile spans collapsed ([#737](#737)) ### Patch Changes - fix: Null-check sentryClient.\_options ([#736](#736)) - Updated dependencies \[[`3d569f30fb746d90ecabaac35d23d980360ea99c`](3d569f3), [`d3a2f0a0fae9074802b0551f3e1662833c1423c9`](d3a2f0a), [`d0315bc2ead9ccea722cc73c6b5fd7d9fed3f4a4`](d0315bc)]: - @spotlightjs/spotlight@2.13.0 ## @spotlightjs/electron@1.7.0 ### Minor Changes - feat: Keep profile spans collapsed ([#737](#737)) ### Patch Changes - fix: Null-check sentryClient.\_options ([#736](#736)) - Updated dependencies \[[`3d569f30fb746d90ecabaac35d23d980360ea99c`](3d569f3), [`7ea7de17b7ccf9f0c8edb8b413176d2f3482780c`](7ea7de1), [`263ba283efa247e05a022d7f1305cbf819e3e783`](263ba28), [`7ac9fd255cfe85d66e79d632e1d309c3e88d8092`](7ac9fd2), [`a76b2dadb28ce8699c80fc81b709050655bd4629`](a76b2da), [`d3a2f0a0fae9074802b0551f3e1662833c1423c9`](d3a2f0a), [`f2a48b05a41f80e08d1666247f7ccae60bc3d9e7`](f2a48b0), [`6d26f0d21b3ae75e3d81e48ceb2d8f727a94420f`](6d26f0d), [`a8f632357d9dcc46187b00724c14dd4423dfa467`](a8f6323), [`9888dbfc6778de910a2aeae9f3e86f0b2f716a18`](9888dbf), [`ced3e736dfef15d368cac202a10eec4eba7508be`](ced3e73)]: - @spotlightjs/overlay@2.14.0 - @spotlightjs/sidecar@1.11.3 ## @spotlightjs/overlay@2.14.0 ### Minor Changes - feat: Keep profile spans collapsed ([#737](#737)) - Swap "Errors" and "Explore" tab places, making "Explore" the default. It makes more sense this way as there is almost ([#758](#758)) guaranteed to have traces in a good setup but not really errors. - Restructured Sentry integration tabs and components ([#765](#765)) - - \#731: Search Bar sticky and fixed overflow across the overlay. ([#740](#740)) - Include filter functionality when searching spans ([#747](#747)) ### Patch Changes - Fixed parsing of envelope data. ([#751](#751)) - fix: Null-check sentryClient.\_options ([#736](#736)) - format node internals correctly in stacktrace ([#739](#739)) - Fixed #738 ([#741](#741)) ## @spotlightjs/spotlight@2.13.0 ### Minor Changes - feat: Keep profile spans collapsed ([#737](#737)) ### Patch Changes - fix: Null-check sentryClient.\_options ([#736](#736)) - Remove obsolete packages from dependencies ([#761](#761)) - Updated dependencies \[[`3d569f30fb746d90ecabaac35d23d980360ea99c`](3d569f3), [`7ea7de17b7ccf9f0c8edb8b413176d2f3482780c`](7ea7de1), [`263ba283efa247e05a022d7f1305cbf819e3e783`](263ba28), [`7ac9fd255cfe85d66e79d632e1d309c3e88d8092`](7ac9fd2), [`a76b2dadb28ce8699c80fc81b709050655bd4629`](a76b2da), [`d3a2f0a0fae9074802b0551f3e1662833c1423c9`](d3a2f0a), [`f2a48b05a41f80e08d1666247f7ccae60bc3d9e7`](f2a48b0), [`6d26f0d21b3ae75e3d81e48ceb2d8f727a94420f`](6d26f0d), [`a8f632357d9dcc46187b00724c14dd4423dfa467`](a8f6323), [`9888dbfc6778de910a2aeae9f3e86f0b2f716a18`](9888dbf), [`ced3e736dfef15d368cac202a10eec4eba7508be`](ced3e73)]: - @spotlightjs/overlay@2.14.0 - @spotlightjs/sidecar@1.11.3 ## @spotlightjs/sidecar@1.11.3 ### Patch Changes - use nanosecond timestamp for captured filenames ([#776](#776)) - Improve DX by always showing the Spotlight URL, even if the sidecar was already running. Makes it easy to cmd/ctrl+click ([#748](#748)) and open in browser. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Related to #731
These changes add filtering to span search
SpanItemtoSpanTree.The results display not only the direct matches but also their hierarchical context up to the root:
Since spans are time-sorted, it would be useful to add a feature like
+<#items>between results. This would allow you to jump directly to the result you’re looking for when debugging. I’ve been using Spotlight for the past few days, and this addition would have been very helpful.Before opening this PR:
pnpm changeset:add