feat: add filter/exclude/copy actions to Event Deltas#1797
feat: add filter/exclude/copy actions to Event Deltas#1797alex-fedotyev wants to merge 44 commits intomainfrom
Conversation
Add interactive filter actions to the Event Deltas chart tooltips, consistent with the filtering UX in the results table and trace drilldown flyout. Users can now hover over a bar in the Event Deltas charts and click Copy, Filter, or Exclude buttons to drill down into the subset of spans defined by the hovered attribute value. - Enhance HDXBarChartTooltip with copy/filter/exclude action buttons - Use controlled tooltip state to keep tooltip interactive on hover - Export AddFilterFn type for reuse across the component chain - Wire onAddFilter from DBSearchPage -> DBSearchHeatmapChart -> DBDeltaChart Closes #1796 Co-authored-by: Alex Fedotyev <alex-fedotyev@users.noreply.github.com>
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
E2E Test Results✅ All tests passed • 75 passed • 4 skipped • 843s
Tests ran across 4 shards in parallel. |
|
@claude - when I tried applying filters, it seems to be erroring out on some of them, likely related to the query generation for resource attributes or span attributes (maps). Investigate what might be causing it, and whether in different parts of the trace filter logic those filters are implemented correctly, so this code would reuse it. Error when filtering using current PR: |
|
Claude finished @alex-fedotyev's task in 14m 48s —— View job Fixed filter generation for Map-type attributes in Event Deltas
Root Cause
The same issue affects Fix —
|
| Flattened key (before) | SQL expression (after) |
|---|---|
ResourceAttributes.service.name |
ResourceAttributes['service.name'] |
SpanAttributes.http.method |
SpanAttributes['http.method'] |
Events.Attributes[0].message.type |
Events.Attributes[1]['message.type'] |
The handleAddFilter callback in DBDeltaChart wraps onAddFilter to apply this conversion. Handles LowCardinality(Map(...)) and Nullable(Map(...)) type wrappers too.
This matches how the rest of the codebase handles map attribute filters — DBRowOverviewPanel explicitly constructs ${resourceAttributesExpression}['${key}'] bracket notation.
Unit tests added in packages/app/src/components/__tests__/DBDeltaChart.test.ts covering all conversion cases.
| Branch
… in Event Deltas filters flattenData() produces dot-notation keys like ResourceAttributes.service.name for Map-type columns, but ClickHouse SQL requires bracket notation for Map access: ResourceAttributes['service.name']. The dot notation causes ClickHouse to attempt tupleElement() on a Map type, which fails. Adds flattenedKeyToSqlExpression() that uses the query result meta (column name + type) to detect Map and Array(Map) columns and convert keys to valid SQL expressions. Also fixes the 0-based (JS) to 1-based (ClickHouse) array index for Array(Map) columns like Events.Attributes. This matches how other parts of the codebase handle map attribute filters: DBRowOverviewPanel uses ResourceAttributesExpression['key'] bracket notation. Co-authored-by: Alex Fedotyev <alex-fedotyev@users.noreply.github.com>
|
@claude - implement following improvement to help navigating the list of attributes based on how useful those values are for the analysis. Make sure to reuse existing components, code and UI as much as possible, avoid re-archtecting. Bring feedback if something isn't possible to implement without major changes.
|
|
Claude finished @alex-fedotyev's task in 15m 14s —— View job Implemented Field Filtering for Event Deltas
What was implemented
1. Structural Denylist — always hidden regardless of cardinality:
Detection is type-based using the 2. Cardinality Filter — hidden when values are too unique to be useful:
3. HiddenFieldsSection component:
4. Pagination update:
New test suites added:
|
Implements field filtering to reduce noise in the Event Deltas chart view: 1. Structural denylist: ID fields (TraceId, SpanId, ParentSpanId, Links.TraceId[N], Links.SpanId[N]) and per-index timestamp arrays (Events.Timestamp[N], Links.Timestamp[N]) are hidden by default. Detection is type-based using columnMeta (String / Array(String) columns ending in Id/ID; Array(DateTime64) columns for timestamps). 2. Cardinality filter: Fields where min(outlierUniqueness, inlierUniqueness) > 0.9 AND combined sample size > 20 are hidden. Uses uniqueValues/propertyOccurences ratio derived from getPropertyStatistics output. 3. HiddenFieldsSection UI: Collapsed by default showing count + preview of first 5 names. Expanded view lists each hidden field with its unique value count and a "Show chart" toggle to inline the full PropertyComparisonChart. 4. Pagination update: Counts only visible fields. A "Showing X of Y fields" note appears near pagination when fields are hidden. Exports isIdField, isTimestampArrayField, isDenylisted, isHighCardinality for unit testing. Unit tests added covering all helpers and the split logic. Co-authored-by: Alex Fedotyev <alex-fedotyev@users.noreply.github.com>
|
@claude - denylist and cardinality filters seem to work well mostly. Change the UX to appreciate the existing pagination, as current implementation didn't follow by adding views at the bottom of it. I suggest to add the denylist to the last page within existing pagination. Charts need to appear exactly same as other charts. Question is whether section needs to have separator - I like it. Should it be collapsed by default? If user expands it, will it change the number of pages depending on how many new attributes need to be displayed and how they fit on the page? Or just keep separator as a visual and logical splitter with lower importance attributes listed at the bottom? |
|
Claude finished @alex-fedotyev's task in 5m 43s —— View job Redesigned lower-priority fields UX
What changedDesign decisions:
Layout on last page: Code cleanup: Removed |
…ination Replace the HiddenFieldsSection component (which rendered below pagination) with an inline section that appears on the last page. Lower-priority fields use the same PropertyComparisonChart component and same CSS grid layout as primary fields. A Divider with label 'Lower-priority fields (N)' provides a clear visual and logical separator. No expand/collapse -- fields are always visible on the last page as static content. Co-authored-by: Alex Fedotyev <alex-fedotyev@users.noreply.github.com>
|
@claude : Improve Event Deltas Chart Tooltip and Legend UX The tooltip follows the mouse cursor, so action buttons move as the user tries to click them Requirements Split Hover and Click into Separate Interactions Click (action popover): Shows when the user clicks a bar Implementation approach: Add onClick handler to the component (Recharts supports this via the onClick prop on ) Fix Axis Labels for Long Values and Many Values Truncated label: max 12 characters, append "…" for longer values <title> SVG element inside the so the full value appears as a native browser tooltip on hover (this complements the Recharts hover tooltip — belt and suspenders) Use the same font size and color as current axis labels This is a small, self-contained functional component — ~15 lines of codeFor 7+ values — show top N with "other" bucket: When a field has more than 6 distinct values, render bars for only the top 6 values by combined frequency (inlier + outlier counts) Order Action Buttons by Importance Match button styling to the patterns already used in the results table and trace flyout for consistency. Look at how those components render their filter/exclude/copy actions and reuse the same button components/styles. Remove the action buttons from HDXBarChartTooltip — it should only render info (value name, count, percentage) The click popover (Section 1 above) replaces the hover-based actions with a cleaner interaction model. Minimize changes to shared components. If HDXBarChart is used outside Event Deltas, add the click behavior via optional props (e.g., onBarClick?: (data) => void) rather than changing default behavior. The click popover state and rendering should live in DBDeltaChart, not in the shared chart component. File Changes Expected packages/app/src/components/DBDeltaChart.tsx — click popover state/rendering, data aggregation for top-N, TruncatedTick component |
|
Claude finished @alex-fedotyev's task in 9m 10s —— View job Improved Event Deltas Chart Tooltip and Legend UX
What changed (
|
- Split hover/click interactions: hover tooltip is now info-only (value name + percentages), click opens an anchored action popover - Click popover (position:fixed, anchored to bar click coordinates) shows Filter -> Exclude -> Copy buttons; Filter/Exclude dismiss popover on action, Copy keeps it open with Copied! feedback - Popover dismisses on click-outside and scroll - Added TruncatedTick custom XAxis tick: truncates to 12 chars + ..., includes native SVG title for full value on hover - Top-6 + Other(N) aggregation: fields with >6 distinct values show top 6 by combined frequency and collapse the rest into a neutral gray Other(N) bucket; click actions disabled on Other bar - Button order: Filter (primary variant) -> Exclude (secondary) -> Copy (secondary, icon-only) - consistent with codebase action patterns - Removed controlled tooltip hover-delay state - Exported applyTopNAggregation and MAX_CHART_VALUES for unit testing - Added unit tests for applyTopNAggregation (7 test cases) Co-authored-by: Alex Fedotyev <alex-fedotyev@users.noreply.github.com>
|
@claude - fix bugs:
|
|
Claude finished @alex-fedotyev's task in 9m 20s —— View job Fixed 4 popup and chart bugs
What changed
|
… persistence bugs - Bug 1 (z-index): Render click popover via createPortal into document.body so it always appears above all chart siblings in the grid layout - Bug 2 (light theme): Replace hardcoded dark-mode CSS variables with theme-aware chartTooltip CSS class (uses --color-bg-surface / --color-border) - Bug 3 (missing title): Add property name header and outlier/inlier counts with percentages to the click popover content - Bug 4 (selection persistence): Pass initialSelection prop from DBSearchHeatmapChart through DBHeatmapChart (HeatmapContainer) to Heatmap; capture uPlot instance via plugin init hook and restore the selection overlay with correct pixel coordinates after the component remounts on filter change Co-authored-by: Alex Fedotyev <alex-fedotyev@users.noreply.github.com>
PR Review
|
|
@claude - fix couple following issues:
|
|
Claude finished @alex-fedotyev's task in 7m 46s —— View job Fixed popup tooltip z-index, chart selection persistence, and lower-priority field pagination
What changedBug 1 — Popup tooltip hints rendering below/behind popover ( Mantine Tooltip components render into a separate Mantine portal that had no explicit z-index. Since the click popover itself is rendered via Bug 2 — Chart selection not restored after applying filter ( Root cause: the uPlot Fix: added Bug 3 — Lower-priority fields causing unbounded last page ( Lower-priority fields are now part of the standard pagination:
|
|
@claude - lint still failing even after latest fixes, can you improve the rest of the items? |
|
Claude finished @alex-fedotyev's task in 4m 8s —— View job Fixed remaining lint errors
3 errors fixed:
|
…Chart and DBDeltaChart tests Co-authored-by: Alex Fedotyev <alex-fedotyev@users.noreply.github.com>
Map keys like "process.runtime.name" are a single key with dots in it, not a nested path. The previous approach quoted each segment separately: toString(ResourceAttributes.\`process\`.\`runtime\`.\`name\`) which ClickHouse interpreted as nested tuple element access and failed with "Unknown expression or function identifier". Now quotes the entire key as one identifier: toString(ResourceAttributes.\`process.runtime.name\`) which correctly accesses the Map key as a single string. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The sidebar wraps facet keys from useGetKeyValues as toString(ResourceAttributes.os.version) — no backtick quoting. Our previous backtick-quoted format didn't match, causing the filter to appear as a separate entry and the sidebar to regenerate it without backticks on checkbox toggle, producing invalid SQL. Now uses the exact same format as the sidebar: toString(ColName.key) with unquoted dot-notation, ensuring filter keys match facet keys and checkboxes work correctly on toggle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rgePath) The trace flyout's "Add to Filters" uses mergePath() which produces per-segment backtick quoting: ResourceAttributes.\`service\`.\`instance\`.\`id\` wrapped in toString(). This format is valid ClickHouse SQL (backticks are identifiers) and matches the sidebar's facet key format. Previous attempts failed because: - Unquoted dots: ClickHouse treats as nested tuple access → error - Single whole-key backtick: didn't match sidebar facet format - Bracket notation: didn't match sidebar facet format Now matches the exact same format as mergePath() in utils.ts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
toString() and backtick-quoting approaches all fail for Map columns with dotted keys — ClickHouse interprets dots as nested tuple access regardless of quoting style. The only format that reliably works is bracket notation: ResourceAttributes['service.instance.id'] This matches what the search bar produces when filtering from trace detail view (WHERE ResourceAttributes['k8s.pod.name'] = 'value'). Trade-off: bracket-notation keys won't match sidebar facet keys (which use toString + backtick format), so filters from the delta chart appear as separate entries rather than matching checkboxes. This is acceptable — the filter works correctly at the SQL level, and improving sidebar compatibility is tracked for a follow-up PR. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix import sort order in DBDeltaChart.test.ts and PropertyComparisonChart.tsx - Fix prettier formatting in test file - Update docstrings in deltaChartUtils.ts and DBDeltaChart.tsx to reflect the bracket-notation filter key format (no longer toString/backtick) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The click popover (Filter/Exclude/Copy actions) was hard to dismiss — clicking elsewhere in the UI didn't close it because the click-outside handler required clicks to be outside both the popover AND the chart wrapper, and Recharts consumed mousedown events on other charts. Now: - Escape key closes the popover - Clicking anywhere outside the popover closes it (simplified check) - Scroll still closes it (unchanged) - All three handlers consolidated into a single useEffect Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>










This PR grew too large during iterative development (2,900+ lines across 8 files, 40+ commits). It has been split into 7 focused issues that can be implemented and reviewed independently:
Issues (in recommended merge order)
Reference implementation
This PR branch (
claude/issue-1796-20260225-0116) contains the complete working implementation with 106 unit tests covering all pure utility functions. The code in this branch serves as the reference for creating the individual PRs above.What this PR contains (for reference)
deltaChartUtils.ts(636 lines) — all pure utility functions, types, and constantsPropertyComparisonChart.tsx(401 lines) — extracted bar chart componentDBDeltaChart.tsx(709 lines) — main orchestration componentDBHeatmapChart.tsx(+279 lines) — heatmap correlation highlights, tooltip fixes, selection UXDBSearchHeatmapChart.tsx(+88 lines) — container wiringDBDeltaChart.test.ts(1,090 lines) — 106 unit testsapp.scss(+7 lines) — selection color overrideDBSearchPage.tsx(+1 line) — onAddFilter propDo not merge this PR directly. Use the individual issues above for focused, reviewable changes.
Original description: Implements #1796 — Improve Traces → Event Deltas by introducing filtering actions for continuous drill down.