Skip to content

feat(app): histogram and filters across every selected source - #2886

Draft
teeohhem wants to merge 1 commit into
tom/n5-nary-results-tablefrom
tom/n6-nary-histogram-filters
Draft

feat(app): histogram and filters across every selected source#2886
teeohhem wants to merge 1 commit into
tom/n5-nary-results-tablefrom
tom/n6-nary-histogram-filters

Conversation

@teeohhem

Copy link
Copy Markdown
Contributor

Stacked on #2885. Completes multi-source search.

#2885 made the results table N-ary but left the histogram and filters sidebar single-source. This finishes both, so multi-source is fully featured rather than a reduced mode.

Histogram and count. The page renders SearchHistogram / SearchTotalCount, which take the same per-source list the table does. One source keeps the full DBTimeChart — severity grouping, series drill-down and focus, the pinned tooltip — because a single source has a severity vocabulary to group by. Several sources can't share one, so they stack a count() series each.

Filters sidebar. DBSearchPageFilters takes a list too, so the sidebar people already use works across a selection: facet fields and values merge, value counts are summed so a percentage describes the whole search, "load more" fans out and unions, and pins (personal and team-shared) read as a union and write to every selected source — pin ServiceName while searching logs and traces and it stays pinned in both. A source whose table lacks a filtered column is excluded with the reason on its status chip instead of quietly returning rows that ignore the filter.

With one source every path is the one it was before: analysis-mode tabs, denoise, shared filters, and dropping percentages when a distribution query fails.

Verified live against the demo stack before this stack was split (the split is provably behavior-preserving: this branch's production code is byte-identical to the verified tree). Single source keeps its tabs, denoise, counts, pins, "Show more" and "More filters"; two sources show 33 merged facet groups including nested LogAttributes and SpanAttributes side by side, logs-only SeverityText next to traces-only StatusCode, summed counts, and pins.


Compound Engineering
Claude Code

@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview Aug 12, 2026 7:19pm
hyperdx-storybook Ready Ready Preview Aug 12, 2026 7:19pm

Request Review

@changeset-bot

changeset-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7a9363b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Minor
@hyperdx/api Minor
@hyperdx/otel-collector Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR completes multi-source search by extending the histogram, total count, filter facets, value distributions, and pinned filters across all selected sources.

  • Builds and executes one histogram/count query per selected source, then merges the responses for display.
  • Merges filter fields, values, distributions, and pinned-filter state across the selected sources.
  • Preserves the existing full-featured chart and analysis behavior for single-source searches.

Confidence Score: 3/5

The PR does not appear safe to merge until duplicate source names retain distinct histogram series and partial source-query failures are disclosed rather than shown as complete aggregates.

The current histogram groups and colors sources by non-unique display name, while its merge path silently omits failed source responses and still renders the remaining histogram and count as a complete result.

Files Needing Attention: packages/app/src/components/SearchHistogram.tsx

Important Files Changed

Filename Overview
packages/app/src/DBSearchPage.tsx Connects per-source search specifications to the histogram, total count, and filters sidebar while preserving the single-source rendering path.
packages/app/src/components/SearchHistogram.tsx Implements per-source histogram querying and aggregation, but duplicate source names still collide and partial query failures still produce undisclosed incomplete aggregates.
packages/app/src/components/DBSearchPageFilters.tsx Changes the filter sidebar to consume multiple source configurations and merge their facets, distributions, columns, and pins.
packages/app/src/components/DBSearchPageFilters/hooks.ts Adds slot-based per-source facet querying and unions the returned fields and values.
packages/app/src/hooks/useMetadata.tsx Adds per-source value-distribution queries and sums counts by value across successful sources.
packages/app/src/searchFilters.tsx Extends pinned-filter state and mutations across the selected source IDs.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Sources[Selected sources] --> Specs[Per-source search specifications]
  Specs --> Queries[Per-source ClickHouse queries]
  Queries --> Histogram[Stacked multi-source histogram]
  Queries --> Count[Summed result count]
  Specs --> Facets[Merged facet fields and values]
  Specs --> Distributions[Summed value distributions]
  Sources --> Pins[Union and fan-out pinned filters]
  Facets --> Sidebar[Filters sidebar]
  Distributions --> Sidebar
  Pins --> Sidebar
Loading

Reviews (2): Last reviewed commit: "feat(app): histogram and filters across ..." | Re-trigger Greptile

Comment on lines +157 to +159
const sourceName = specs[i].source.name;
for (const row of response.data ?? []) {
data.push({ ...row, [SOURCE_GROUP_COLUMN]: sourceName });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Source-name series identity collision

When two selected sources have the same display name, both responses receive the same __hdx_source group value, causing the chart transform to collapse them into one series and the name-keyed color map to retain only one source color.

Knowledge Base Used: App Components and Charts

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

Comment on lines +137 to +142
const isLoading = slots.some(s => s.isLoading);
const allFailed = slots.length > 0 && slots.every(s => s.isError);
const anyError = slots.some(s => s.isError);
const error = slots.find(s => s.error != null)?.error ?? undefined;
const isComplete =
slots.length > 0 && slots.every(s => s.isError || !!s.data?.isComplete);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Partial query failures look complete

When one source query fails while another succeeds, the merge omits the failed source and only renders an error when every source fails, causing the histogram and total count to present an incomplete aggregate without disclosing it.

Knowledge Base Used: App Components and Charts

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

Comment on lines +144 to +147
const mergedResponse: ResponseJSON<Record<string, any>> | undefined =
useMemo(() => {
let meta: ColumnMetaType[] | undefined;
const data: Record<string, any>[] = [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Untyped oversized chart implementation

The new 421-line component combines querying, aggregation, formatting, and rendering while using any for response rows; NestedFilterGroup also introduces any[] for chart configurations. This bypasses the repository's proper-typing and 300-line component requirements, reducing compile-time protection and making the feature harder to maintain.

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

The results table already spanned sources; the histogram and the filters
sidebar still picked a component per case at the call site.

The page now renders SearchHistogram and SearchTotalCount, which take the
same per-source list the table does. One source keeps the full DBTimeChart
— severity grouping, series drill-down and focus, the pinned tooltip —
because a single source has a severity vocabulary to group by. Several
sources can't share one, so they stack a count() series each.

DBSearchPageFilters takes a list too, so the sidebar people already use
works across a selection: facet fields and values merge, value counts are
summed so a percentage describes the whole search, "load more" fans out
and unions, and pins read as a union and write to every selected source.
A source whose table lacks a filtered column is excluded from the results
with the reason on its status chip, rather than quietly returning rows
that ignore the filter.

With one source every path is the one it was before: analysis-mode tabs,
denoise, shared filters, and dropping percentages when a distribution
query fails.
@teeohhem
teeohhem force-pushed the tom/n6-nary-histogram-filters branch from c6e26b2 to 7a9363b Compare August 12, 2026 19:14
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 279 passed • 1 skipped • 1153s

Status Count
✅ Passed 279
❌ Failed 0
⚠️ Flaky 3
⏭️ Skipped 1

Tests ran across 4 shards in parallel.

View full report →

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant