Skip to content

prototype(dashboards): Heatmap#111757

Open
marthalyndon wants to merge 4 commits intomasterfrom
martha-peck/prototype-metrics-heatmap
Open

prototype(dashboards): Heatmap#111757
marthalyndon wants to merge 4 commits intomasterfrom
martha-peck/prototype-metrics-heatmap

Conversation

@marthalyndon
Copy link
Copy Markdown
Contributor

@marthalyndon marthalyndon commented Mar 27, 2026

Prototype of adding a heatmap to metrics, purpose is to explore different color options.

Never intended to merge in.

marthalyndon and others added 2 commits March 26, 2026 14:24
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>
@marthalyndon marthalyndon requested review from a team as code owners March 27, 2026 21:07
@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Mar 27, 2026
@gggritso gggritso changed the title Martha peck/prototype metrics heatmap prototype(dashboards): Heatmap Mar 27, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

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 Container using equivalent padding, background, and border props and removed the styled component.

Create PR

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.

Comment thread static/app/views/explore/spans/charts/index.tsx Outdated
Comment thread static/app/views/explore/metrics/metricHeatmap.tsx Outdated
Comment thread static/app/views/explore/metrics/metricsTab.tsx
… 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>
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

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';
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.

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)
Fix in Cursor Fix in Web

const METRICS_CHART_TYPE_OPTIONS = [
...EXPLORE_CHART_TYPE_OPTIONS,
{value: ChartType.HEATMAP, label: t('Heatmap')},
];
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.

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.

Fix in Cursor Fix in Web

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

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant