Conversation
Adds a new Heatmap option to the chart type selector on the metrics explore page. Includes a new MetricHeatmap component that renders a color-scaled 2D grid (time x value buckets) using the design spec color palette. WIP: local dev environment not loading — needs eng help to troubleshoot devserver setup. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rewrites MetricHeatmap using HeatMapChart (ECharts 5) with piecewise visualMap, hover emphasis, universalTransition, and proper tooltip styling matching other chart types - Updates heatmap color palette to accessible lavender→violet→crimson gradient interpolated across three design stops - Moves MetricsQueryBuilderSection from left sidebar to full-width top bar; each metric row is now a horizontal Grid row - Removes sidebar expand/collapse state and chevron button - Restores MetricSaveAs to the filter bar for all layouts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for all 3 issues found in the latest run.
- ✅ Fixed: Heatmap option leaks into views without rendering support
- I removed heatmap from the shared explore chart options and added a metrics-only chart option list that appends heatmap where rendering support exists.
- ✅ Fixed: Spread on large array risks stack overflow
- I replaced spread-based min/max computation with iterative scanning so very large datasets no longer pass huge argument lists to Math functions.
- ✅ Fixed: New styled component can use Container core component
- I replaced the new MetricsControlBar styled div with a
Containerusing equivalent padding, background, and border props and removed the styled component.
- I replaced the new MetricsControlBar styled div with a
Or push these changes by commenting:
@cursor push a661a56900
Preview (a661a56900)
diff --git a/static/app/views/explore/metrics/metricGraph/index.tsx b/static/app/views/explore/metrics/metricGraph/index.tsx
--- a/static/app/views/explore/metrics/metricGraph/index.tsx
+++ b/static/app/views/explore/metrics/metricGraph/index.tsx
@@ -55,6 +55,13 @@
const MINIMIZED_GRAPH_HEIGHT = 50;
const STACKED_GRAPH_HEIGHT = 362;
+const METRICS_CHART_TYPE_OPTIONS = [
+ ...EXPLORE_CHART_TYPE_OPTIONS,
+ {
+ value: ChartType.HEATMAP,
+ label: t('Heatmap'),
+ },
+];
interface MetricsGraphProps {
orientation: TableOrientation;
@@ -239,7 +246,7 @@
)}
value={visualize.chartType}
menuTitle="Type"
- options={EXPLORE_CHART_TYPE_OPTIONS}
+ options={METRICS_CHART_TYPE_OPTIONS}
onChange={option => onChartTypeChange(option.value)}
/>
<CompactSelect
diff --git a/static/app/views/explore/metrics/metricHeatmap.tsx b/static/app/views/explore/metrics/metricHeatmap.tsx
--- a/static/app/views/explore/metrics/metricHeatmap.tsx
+++ b/static/app/views/explore/metrics/metricHeatmap.tsx
@@ -72,8 +72,17 @@
return {data: [], timestamps: [], yLabels: [], minVal: 0, maxVal: 0};
}
- const minVal = Math.min(...allValues);
- const maxVal = Math.max(...allValues);
+ let minVal = allValues[0]!;
+ let maxVal = allValues[0]!;
+ for (let i = 1; i < allValues.length; i++) {
+ const value = allValues[i]!;
+ if (value < minVal) {
+ minVal = value;
+ }
+ if (value > maxVal) {
+ maxVal = value;
+ }
+ }
const range = maxVal - minVal || 1;
const timestampSet = new Set<number>();
@@ -104,7 +113,14 @@
}
}
- const maxCount = Math.max(...counts.flatMap(row => row), 1);
+ let maxCount = 1;
+ for (const row of counts) {
+ for (const count of row) {
+ if (count > maxCount) {
+ maxCount = count;
+ }
+ }
+ }
// Build flat [xIndex, yIndex, intensity] array for ECharts.
// Always emit every cell (including empty ones at intensity 0) so the tooltip
diff --git a/static/app/views/explore/metrics/metricsTab.tsx b/static/app/views/explore/metrics/metricsTab.tsx
--- a/static/app/views/explore/metrics/metricsTab.tsx
+++ b/static/app/views/explore/metrics/metricsTab.tsx
@@ -94,7 +94,7 @@
if (canUseMetricsUIRefresh(organization)) {
return (
- <MetricsControlBar>
+ <Container padding="lg" background="primary" borderBottom="primary">
<Flex direction="column" gap="sm" width="100%">
{metricQueries.map((metricQuery, index) => {
return (
@@ -119,7 +119,7 @@
/>
</Flex>
</Flex>
- </MetricsControlBar>
+ </Container>
);
}
@@ -221,9 +221,3 @@
border-top: none;
border-bottom: 1px solid ${p => p.theme.tokens.border.primary};
`;
-
-const MetricsControlBar = styled('div')`
- padding: ${p => p.theme.space.lg};
- background-color: ${p => p.theme.tokens.background.primary};
- border-bottom: 1px solid ${p => p.theme.tokens.border.primary};
-`;
diff --git a/static/app/views/explore/spans/charts/index.tsx b/static/app/views/explore/spans/charts/index.tsx
--- a/static/app/views/explore/spans/charts/index.tsx
+++ b/static/app/views/explore/spans/charts/index.tsx
@@ -67,10 +67,6 @@
value: ChartType.BAR,
label: t('Bar'),
},
- {
- value: ChartType.HEATMAP,
- label: t('Heatmap'),
- },
];
const EXPLORE_CHART_GROUP = 'explore-charts_group';This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
… Application Metrics - Add useMockHeatmapData hook: simulates multi-dim endpoint response with bimodal Gaussian heat distribution (count() + avg() modes), soft exponential falloff, 30-min fixed grid, no y < 0 - Replace buildHeatmapData in MetricHeatmap with mock hook - Move ChartType.HEATMAP to METRICS_CHART_TYPE_OPTIONS so it no longer leaks into spans/logs/multi-query chart pickers - Replace MetricsControlBar styled div with Container core component - Rename page title and breadcrumb to "Application Metrics" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| datePageFilterProps: DatePageFilterProps; | ||
| }; | ||
|
|
||
| const METRICS_TOOLBAR_STORAGE_KEY = 'explore-metrics-toolbar'; |
There was a problem hiding this comment.
Redundant component renders identical JSX as fallback
Low Severity
MetricsTabContentRefreshLayout now renders exactly the same JSX as the non-refresh fallback in MetricsTabContent. After removing the collapsible sidebar (ExploreBodyContent wrapper, controlSectionExpanded state, etc.), both code paths became identical. The entire MetricsTabContentRefreshLayout function and the canUseMetricsUIRefresh check in MetricsTabContent are now dead code—the conditional branch adds no value over the default path.
Additional Locations (1)
| const METRICS_CHART_TYPE_OPTIONS = [ | ||
| ...EXPLORE_CHART_TYPE_OPTIONS, | ||
| {value: ChartType.HEATMAP, label: t('Heatmap')}, | ||
| ]; |
There was a problem hiding this comment.
Variable declaration placed between import statements
Low Severity
METRICS_CHART_TYPE_OPTIONS is declared between import statements (after line 40's import and before line 46's import). It references ChartType.HEATMAP, which is imported 10 lines later at line 53. This works due to JavaScript import hoisting, but it's a confusing pattern that makes the module structure hard to follow and obscures the dependency on ChartType.



Prototype of adding a heatmap to metrics, purpose is to explore different color options.
Never intended to merge in.