Skip to content

feat(dashboards): Web Vitals page overview dashboard migration #105002

Merged
edwardgou-sentry merged 5 commits intomasterfrom
egou/feat/web-vitals-page-overview-migration-progress
Dec 17, 2025
Merged

feat(dashboards): Web Vitals page overview dashboard migration #105002
edwardgou-sentry merged 5 commits intomasterfrom
egou/feat/web-vitals-page-overview-migration-progress

Conversation

@edwardgou-sentry
Copy link
Copy Markdown
Contributor

  • Adds config for prebuilt web vitals page overview dashboard
  • Adds web vital score meters widgets to overview dashboard
  • Update timeseries order in overview breakdown chart

@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Dec 15, 2025
@codecov
Copy link
Copy Markdown

codecov bot commented Dec 15, 2025

❌ 4 Tests Failed:

Tests completed Failed Passed Skipped
12888 4 12884 10
View the top 3 failed test(s) by shortest run time
PageOverview renders
Stack Traces | 0.028s run time
Error: expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected)

n: 1
Expected: Anything, ObjectContaining {"query": ObjectContaining {"dataset": "spans", "field": ["p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "count()"], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"] !transaction:\"<< unparameterized >>\""}}
Received
->     1: "....../organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"dataset": "spans", "environment": [], "field": ["p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "count()"], "per_page": 50, "project": [], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"]", "referrer": "api.insights.web-vitals.project", "sampling": "NORMAL", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}
       2: "....../organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"cursor": "", "dataset": "spans", "environment": [], "field": ["performance_score(measurements.score.lcp)", "performance_score(measurements.score.fcp)", "performance_score(measurements.score.cls)", "performance_score(measurements.score.inp)", "performance_score(measurements.score.ttfb)", "performance_score(measurements.score.total)", "avg(measurements.score.weight.lcp)", "avg(measurements.score.weight.fcp)", "avg(measurements.score.weight.cls)", "avg(measurements.score.weight.inp)", …], "per_page": 50, "project": [], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"]", "referrer": "api.insights.web-vitals.project-scores", "sampling": "NORMAL", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}

Number of calls: 2
    at Object.toHaveBeenNthCalledWith (.../webVitals/views/pageOverview.spec.tsx:89:24)
    at Promise.finally.completed (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/jestAdapterInit.js:1559:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/jestAdapterInit.js:1499:10)
    at _callCircusTest (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/jestAdapterInit.js:1009:40)
    at processTicksAndRejections (node:internal/process/task_queues:105:5)
    at _runTest (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/jestAdapterInit.js:949:3)
    at _runTestsForDescribeBlock (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/jestAdapterInit.js:839:13)
    at _runTestsForDescribeBlock (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/jestAdapterInit.js:829:11)
    at run (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/jestAdapterInit.js:757:3)
    at runAndTransformResultsToJestFormat (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/jestAdapterInit.js:1920:21)
    at jestAdapter (.../sentry/node_modules/.pnpm/[email protected][email protected]..../jest-circus/build/runner.js:101:19)
    at runTestInternal (.../sentry/node_modules/.pnpm/[email protected]..../jest-runner/build/testWorker.js:272:16)
    at runTest (.../sentry/node_modules/.pnpm/[email protected]..../jest-runner/build/testWorker.js:340:7)
    at Object.worker (.../sentry/node_modules/.pnpm/[email protected]..../jest-runner/build/testWorker.js:494:12)
WebVitalsDetailPanel renders correctly with empty results
Stack Traces | 0.09s run time
Error: expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected)

n: 1
Expected: Anything, ObjectContaining {"query": ObjectContaining {"dataset": "spans", "field": ["p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "count()"], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"] !transaction:\"<< unparameterized >>\""}}
Received
->     1: "....../organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"dataset": "spans", "environment": [], "field": ["p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "count()"], "per_page": 50, "project": [], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"]", "referrer": "api.insights.web-vitals.project", "sampling": "NORMAL", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}
       2: "....../organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"cursor": "", "dataset": "spans", "environment": [], "field": ["performance_score(measurements.score.lcp)", "performance_score(measurements.score.fcp)", "performance_score(measurements.score.cls)", "performance_score(measurements.score.inp)", "performance_score(measurements.score.ttfb)", "performance_score(measurements.score.total)", "avg(measurements.score.weight.lcp)", "avg(measurements.score.weight.fcp)", "avg(measurements.score.weight.cls)", "avg(measurements.score.weight.inp)", …], "per_page": 50, "project": [], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"]", "referrer": "api.insights.web-vitals.project-scores", "sampling": "NORMAL", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}

Number of calls: 3
    at Object.toHaveBeenNthCalledWith (.../webVitals/components/webVitalsDetailPanel.spec.tsx:55:24)
Performance > Widgets > WidgetContainer Best Page Opportunities widget
Stack Traces | 0.143s run time
Error: expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected)

n: 2
Expected: Anything, ObjectContaining {"query": ObjectContaining {"dataset": "spans", "field": ["project.id", "project", "transaction", "p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "opportunity_score(measurements.score.total)", "performance_score(measurements.score.total)", …], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"] !transaction:\"<< unparameterized >>\" avg(measurements.score.total):>=0"}}
Received
       1: "....../organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"cursor": "", "dataset": "spans", "environment": [], "field": ["performance_score(measurements.score.lcp)", "performance_score(measurements.score.fcp)", "performance_score(measurements.score.cls)", "performance_score(measurements.score.inp)", "performance_score(measurements.score.ttfb)", "performance_score(measurements.score.total)", "avg(measurements.score.weight.lcp)", "avg(measurements.score.weight.fcp)", "avg(measurements.score.weight.cls)", "avg(measurements.score.weight.inp)", …], "per_page": 50, "project": [], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"]", "referrer": "api.insights.web-vitals.project-scores", "sampling": "NORMAL", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}
->     2: "....../organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"dataset": "spans", "environment": [], "field": ["project.id", "project", "transaction", "p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "opportunity_score(measurements.score.total)", "performance_score(measurements.score.total)", …], "per_page": 4, "project": [], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"] avg(measurements.score.total):>=0", "referrer": "api.insights.web-vitals.transactions-scores", "sampling": "NORMAL", "sort": "-count()", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}

Number of calls: 2
    at Object.toHaveBeenNthCalledWith (.../widgets/components/widgetContainer.spec.tsx:946:24)
    at runNextTicks (node:internal/process/task_queues:65:5)
    at listOnTimeout (node:internal/timers:549:9)
    at processTimers (node:internal/timers:523:7)
WebVitalsLandingPage renders
Stack Traces | 0.384s run time
Error: expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected)

n: 2
Expected: Anything, ObjectContaining {"query": ObjectContaining {"dataset": "spans", "field": ["project.id", "project", "transaction", "p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "opportunity_score(measurements.score.total)", "performance_score(measurements.score.total)", …], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"] !transaction:\"<< unparameterized >>\" avg(measurements.score.total):>=0"}}
Received
       1: "........./organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"dataset": "spans", "environment": [], "field": ["user.geo.subregion", "count()"], "per_page": 50, "project": [], "query": "has:user.geo.subregion", "referrer": "api.insights.user-geo-subregion-selector", "sampling": "NORMAL", "sort": "-count()", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}
->     2: "........./organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"dataset": "spans", "environment": [], "field": ["project.id", "project", "transaction", "p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "opportunity_score(measurements.score.total)", "performance_score(measurements.score.total)", …], "per_page": 25, "project": [], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"] avg(measurements.score.total):>=0", "referrer": "api.insights.web-vitals.transactions-scores", "sampling": "NORMAL", "sort": "-opportunity_score(measurements.score.total)", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}
       3: "........./organizations/org-slug/events/", {"error": [Function error], "method": "GET", "query": {"dataset": "spans", "environment": [], "field": ["p75(measurements.lcp)", "p75(measurements.fcp)", "p75(measurements.cls)", "p75(measurements.ttfb)", "p75(measurements.inp)", "count()"], "per_page": 50, "project": [], "query": "span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,ui.webvital.cls,ui.webvital.lcp,pageload,\"\"]", "referrer": "api.insights.web-vitals.project", "sampling": "NORMAL", "statsPeriod": "14d"}, "skipAbort": undefined, "success": [Function success]}

Number of calls: 4
    at Object.toHaveBeenNthCalledWith (.../webVitals/views/webVitalsLandingPage.spec.tsx:100:24)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@edwardgou-sentry edwardgou-sentry marked this pull request as ready for review December 16, 2025 00:48
@edwardgou-sentry edwardgou-sentry requested a review from a team as a code owner December 16, 2025 00:48
@edwardgou-sentry edwardgou-sentry requested a review from a team December 16, 2025 00:48
Copy link
Copy Markdown
Member

@gggritso gggritso left a comment

Choose a reason for hiding this comment

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

Fractional layout is too risky IMO, but I leave it to you 🙏🏻

Copy link
Copy Markdown
Member

@narsaynorath narsaynorath left a comment

Choose a reason for hiding this comment

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

Code lgtm, but I agree with George, the fractions feel a little odd because I wonder what happens if we get to a state where we can actual copy + move widgets around in the dashboard. Since this is feature flagged it's all good to me for now

@edwardgou-sentry
Copy link
Copy Markdown
Contributor Author

👍 updated to use integers for the layouts. I'll try to figure out what the solution is with Ben

@edwardgou-sentry edwardgou-sentry merged commit d9e229b into master Dec 17, 2025
48 checks passed
@edwardgou-sentry edwardgou-sentry deleted the egou/feat/web-vitals-page-overview-migration-progress branch December 17, 2025 16:31
@github-actions github-actions bot locked and limited conversation to collaborators Jan 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants