refactor(app): declarative Infrastructure tab correlation list#2462
refactor(app): declarative Infrastructure tab correlation list#2462alex-fedotyev wants to merge 3 commits into
Conversation
Turn the hardcoded Pod and Node correlation blocks in DBInfraPanel and the matching gate in rowHasK8sContext into a shared declarative descriptor list (detect attribute, correlate attribute, field prefix, chart specs, optional timeline). The gate and the renderer now read from the same list, so they cannot drift apart, and the detect attribute is separated from the correlate attribute so resource types that key on different attributes can be added as data rather than new code paths. No behavior change: the same Infrastructure tab, gate, Pod and Node charts, Pod Timeline, time and size toggles, and Event marker render identically for Kubernetes rows. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
🟡 Tier 3 — StandardIntroduces new logic, modifies core functionality, or touches areas with non-trivial risk. Why this tier:
Review process: Full human review — logic, architecture, edge cases. Stats
|
Greptile SummaryThis PR refactors the Infrastructure tab from two hardcoded Kubernetes blocks (Pod and Node) into a descriptor-driven loop backed by a new
Confidence Score: 5/5Safe to merge. The refactor is a 1:1 behavioral replacement for all current Kubernetes paths; the descriptor types are fully readonly; the gate and renderer now share a single function. All current Kubernetes code paths are reproduced byte-identically through the descriptor list. The No files require special attention for this merge. The timeline query attribute observation in Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Row opened in side panel] --> B{rowHasK8sContext}
B -->|calls| C[getActiveInfraCorrelations\nresourceAttributes]
C --> D{Filter INFRA_CORRELATIONS\nby detectAttribute != null}
D -->|length > 0| E[Show Infrastructure tab]
D -->|length === 0| F[Hide Infrastructure tab]
E --> G[DBInfraPanel renders]
G --> H[activeCorrelations loop]
H --> I{correlateAttribute\nvalue truthy?}
I -->|no| J[skip / return null]
I -->|yes| K[InfraSubpanelGroup\ncharts.map → DBTimeChart]
K --> L{timeline\n&& Log source?}
L -->|yes| M[KubeTimeline]
L -->|no| N[metrics only]
Reviews (3): Last reviewed commit: "test(app): assert Infrastructure tab is ..." | Re-trigger Greptile |
| const value = resourceAttributes?.[correlation.correlateAttribute]; | ||
| if (!value) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
The render guard uses falsy semantics (
!value) while getActiveInfraCorrelations (the gate) uses != null. They should match. For the current Kubernetes descriptors where detectAttribute === correlateAttribute and the value is always a non-empty string, this is harmless — but the declared purpose of separating detectAttribute from correlateAttribute is to let a future descriptor detect on one attribute and correlate on another. If that future correlateAttribute holds an empty string, 0, or false, the gate would pass (the Infrastructure tab would appear) while the render guard would silently skip every group, leaving the panel empty.
| const value = resourceAttributes?.[correlation.correlateAttribute]; | |
| if (!value) { | |
| return null; | |
| } | |
| const value = resourceAttributes?.[correlation.correlateAttribute]; | |
| if (value == null) { | |
| return null; | |
| } |
E2E Test Results✅ All tests passed • 200 passed • 3 skipped • 1307s
Tests ran across 4 shards in parallel. |
Mark the InfraCorrelation / InfraChartSpec descriptor data (including the shared K8S_CHART_SPECS array reused by the Pod and Node groups) as readonly so the shared reference cannot be mutated through one descriptor and affect the other. No behavior change. Also document that the render-time truthiness guard intentionally mirrors the prior Pod/Node render blocks; the tab gate uses != null, and the two only diverge once a descriptor splits its detect and correlate attributes, which is handled when such a descriptor is added. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Handled the two notes from the automated review in cb274b8:
|
Adds an e2e negative case: open a non-Kubernetes log row and confirm the Infrastructure tab is not offered. This locks the gate (the tab appears only when a built-in correlation's detect attribute is present) at the rendered-UI level, complementing the existing positive case that asserts the Pod and Node charts render for a k8s row. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
The Infrastructure tab in the log and trace row side panel correlates infrastructure metrics to the opened span. Until now it was hardcoded to exactly two Kubernetes resource types, Pod and Node, with three fixed charts each, and it used a single attribute both to decide whether a group should appear and to filter that group's metrics.
This refactors that hardcoding into a declarative descriptor list and splits the "detect" attribute (decides whether a group shows up) from the "correlate" attribute (filters the group's metrics). Kubernetes behavior is unchanged: the same tab, the same gate, the same Pod and Node charts, the Pod Timeline, the time and size toggles, and the Event marker all render identically.
There is no functional or visual change. The value is internal. The gate and the renderer now read from one shared descriptor list, so they cannot drift apart, and adding a new resource type later (host metrics, serverless functions) becomes a matter of appending a descriptor rather than adding a parallel code path.
What changed
packages/app/src/components/infraCorrelations.ts: anInfraCorrelationdescriptor type (detect attribute, correlate attribute, field prefix, chart specs, optional timeline), the built-in Kubernetes Pod and Node descriptors, and agetActiveInfraCorrelations(resourceAttributes)selector.DBInfraPanel.tsx:InfraSubpanelGroupmaps over a descriptor's chart specs instead of three hardcoded cards, and the panel maps over the active descriptors instead of two hardcoded Pod and Node blocks. The Pod Timeline is driven by a descriptor flag.DBRowDataPanel.tsx:rowHasK8sContext, the gate shared by the row side panel and the trace panel, now delegates togetActiveInfraCorrelations(...).length > 0. For the Kubernetes descriptor set this is identical to the previousk8s.pod.uid != null || k8s.node.name != nullcheck.One structural note: each correlation group is now wrapped in a container
div(previously only the Pod group was, to keep its charts and timeline together). The wrapper has no styling, so the rendered output is unchanged; it also avoids a stray gap that the old code could leave when a group had nothing to show.Verification
k8s.pod.cpu.utilization - Gaugeand the rest), chart titles, number formats, carddata-testids, and the Pod Timeline query, and the gate keeps the samek8s.pod.uid != null || k8s.node.name != nulltruth table. I went through the before and after of every generated string to confirm byte-for-byte equality.infraCorrelations.test.tslocks the selector's gate semantics (Pod-only, Node-only, both, neither, unrelated attributes, null handling) and pins the built-in descriptor identity (field prefixes, metric fields, card test ids, Pod-only timeline).correlated-metric-sourcespec covers the "no correlated metric source" path, and a new negative case (Infrastructure tab is hidden for non-Kubernetes rows) asserts the gate hides the tab on a non-k8s row.avg(k8s.pod.*)/avg(k8s.node.*), the Pod Timeline, the Event reference line, and the 30m/1h/1d + SM/MD/LG toggles). The only differences were the underlying demo data. Preview: https://hyperdx-oss-git-alex-infra-declarative-correlation-hyperdx.vercel.app/searchTest plan
tsc --noEmitcleaninfraCorrelations.test.ts(10 cases) greenDBRowDataPanel,DBTracePanel) green[ui-states: allow] no new empty, loading, or error states; the existing alert and loading paths are unchanged.
[viewport: allow] no layout change; the SimpleGrid column logic is untouched.
[no-changeset: allow] internal refactor with no user-visible effect.