Browse Source

fix(webvitals): fixes webvitals landing page tables empty states + other misc fixes (#61712)

- Fixes the webvitals landing page table to properly display empty cells
on rows that are missing a webvital.
- Updates the landing page slideout panel to filter for only pages with
the selected webvital. This reduces the amount of irrelevant pages in
the webvital slideout.
- Page Overview sidebar also shows dynamic weights
- Fixed an issue with performance score calculation on the webvitals
landing page when a page is missing 1 or more webvitals.
edwardgou-sentry 1 year ago
parent
commit
636fdef777

+ 13 - 1
static/app/views/performance/browser/webVitals/components/pageOverviewSidebar.tsx

@@ -16,8 +16,8 @@ import usePageFilters from 'sentry/utils/usePageFilters';
 import useRouter from 'sentry/utils/useRouter';
 import {MiniAggregateWaterfall} from 'sentry/views/performance/browser/webVitals/components/miniAggregateWaterfall';
 import PerformanceScoreRingWithTooltips from 'sentry/views/performance/browser/webVitals/components/performanceScoreRingWithTooltips';
-import {ProjectScore} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/calculatePerformanceScore';
 import {useProjectRawWebVitalsValuesTimeseriesQuery} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/useProjectRawWebVitalsValuesTimeseriesQuery';
+import {ProjectScore} from 'sentry/views/performance/browser/webVitals/utils/types';
 import {SidebarSpacer} from 'sentry/views/performance/transactionSummary/utils';
 
 const CHART_HEIGHTS = 100;
@@ -114,6 +114,17 @@ export function PageOverviewSidebar({
   const ringSegmentColors = theme.charts.getColorPalette(3);
   const ringBackgroundColors = ringSegmentColors.map(color => `${color}50`);
 
+  // Gets weights to dynamically size the performance score ring segments
+  const weights = projectScore
+    ? {
+        cls: projectScore.clsWeight,
+        fcp: projectScore.fcpWeight,
+        fid: projectScore.fidWeight,
+        lcp: projectScore.lcpWeight,
+        ttfb: projectScore.ttfbWeight,
+      }
+    : undefined;
+
   return (
     <Fragment>
       <SectionHeading>
@@ -141,6 +152,7 @@ export function PageOverviewSidebar({
             height={180}
             ringBackgroundColors={ringBackgroundColors}
             ringSegmentColors={ringSegmentColors}
+            weights={weights}
           />
         )}
         {projectScoreIsLoading && <ProjectScoreEmptyLoadingElement />}

+ 3 - 3
static/app/views/performance/browser/webVitals/components/performanceScoreRingWithTooltips.tsx

@@ -12,11 +12,11 @@ import useMouseTracking from 'sentry/utils/replays/hooks/useMouseTracking';
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 import PerformanceScoreRing from 'sentry/views/performance/browser/webVitals/components/performanceScoreRing';
+import {PERFORMANCE_SCORE_WEIGHTS} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/calculatePerformanceScore';
 import {
-  PERFORMANCE_SCORE_WEIGHTS,
   ProjectScore,
-} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/calculatePerformanceScore';
-import {WebVitals} from 'sentry/views/performance/browser/webVitals/utils/types';
+  WebVitals,
+} from 'sentry/views/performance/browser/webVitals/utils/types';
 
 import {ORDER} from '../performanceScoreChart';
 

+ 4 - 3
static/app/views/performance/browser/webVitals/components/webVitalDescription.tsx

@@ -13,11 +13,12 @@ import {Tag} from 'sentry/types';
 import {WebVital} from 'sentry/utils/fields';
 import {Browser} from 'sentry/utils/performance/vitals/constants';
 import {getScoreColor} from 'sentry/views/performance/browser/webVitals/utils/getScoreColor';
-import {WebVitals} from 'sentry/views/performance/browser/webVitals/utils/types';
+import {
+  ProjectScore,
+  WebVitals,
+} from 'sentry/views/performance/browser/webVitals/utils/types';
 import {vitalSupportedBrowsers} from 'sentry/views/performance/vitalDetail/utils';
 
-import {ProjectScore} from '../utils/queries/rawWebVitalsQueries/calculatePerformanceScore';
-
 import PerformanceScoreRingWithTooltips from './performanceScoreRingWithTooltips';
 
 type Props = {

+ 7 - 5
static/app/views/performance/browser/webVitals/components/webVitalMeters.tsx

@@ -11,12 +11,14 @@ import {space} from 'sentry/styles/space';
 import {TableData} from 'sentry/utils/discover/discoverQuery';
 import {getDuration} from 'sentry/utils/formatters';
 import {PERFORMANCE_SCORE_COLORS} from 'sentry/views/performance/browser/webVitals/utils/performanceScoreColors';
-import {ProjectScore} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/calculatePerformanceScore';
 import {
   scoreToStatus,
   STATUS_TEXT,
 } from 'sentry/views/performance/browser/webVitals/utils/scoreToStatus';
-import {WebVitals} from 'sentry/views/performance/browser/webVitals/utils/types';
+import {
+  ProjectScore,
+  WebVitals,
+} from 'sentry/views/performance/browser/webVitals/utils/types';
 
 type Props = {
   onClick?: (webVital: WebVitals) => void;
@@ -65,7 +67,7 @@ export default function WebVitalMeters({
     <Container>
       <Flex>
         {webVitals.map(webVital => {
-          const webVitalExists = projectScore[`${webVital}Score`] !== null;
+          const webVitalExists = projectScore[`${webVital}Score`] !== undefined;
           const formattedMeterValueText = webVitalExists ? (
             WEB_VITALS_METERS_CONFIG[webVital].formatter(
               projectData?.data?.[0]?.[`p75(measurements.${webVital})`] as number
@@ -177,8 +179,8 @@ const MeterValueText = styled('div')`
   text-align: center;
 `;
 
-function MeterBarFooter({score}: {score: number | null}) {
-  if (score === null) {
+function MeterBarFooter({score}: {score: number | undefined}) {
+  if (score === undefined) {
     return (
       <MeterBarFooterContainer status="none">{t('No Data')}</MeterBarFooterContainer>
     );

+ 7 - 9
static/app/views/performance/browser/webVitals/pageOverview.tsx

@@ -29,15 +29,15 @@ import {PageOverviewSidebar} from 'sentry/views/performance/browser/webVitals/co
 import {PerformanceScoreBreakdownChart} from 'sentry/views/performance/browser/webVitals/components/performanceScoreBreakdownChart';
 import WebVitalMeters from 'sentry/views/performance/browser/webVitals/components/webVitalMeters';
 import {PageOverviewWebVitalsDetailPanel} from 'sentry/views/performance/browser/webVitals/pageOverviewWebVitalsDetailPanel';
-import {
-  PageSamplePerformanceTable,
-  TransactionSampleRowWithScoreAndExtra,
-} from 'sentry/views/performance/browser/webVitals/pageSamplePerformanceTable';
+import {PageSamplePerformanceTable} from 'sentry/views/performance/browser/webVitals/pageSamplePerformanceTable';
 import {calculatePerformanceScoreFromTableDataRow} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/calculatePerformanceScore';
 import {useProjectRawWebVitalsQuery} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/useProjectRawWebVitalsQuery';
 import {calculatePerformanceScoreFromStoredTableDataRow} from 'sentry/views/performance/browser/webVitals/utils/queries/storedScoreQueries/calculatePerformanceScoreFromStored';
 import {useProjectWebVitalsScoresQuery} from 'sentry/views/performance/browser/webVitals/utils/queries/storedScoreQueries/useProjectWebVitalsScoresQuery';
-import {WebVitals} from 'sentry/views/performance/browser/webVitals/utils/types';
+import {
+  TransactionSampleRowWithScore,
+  WebVitals,
+} from 'sentry/views/performance/browser/webVitals/utils/types';
 import {useStoredScoresSetting} from 'sentry/views/performance/browser/webVitals/utils/useStoredScoresSetting';
 import {ModulePageProviders} from 'sentry/views/performance/database/modulePageProviders';
 
@@ -59,9 +59,7 @@ const LANDING_DISPLAYS = [
   },
 ];
 
-const SAMPLES_COLUMN_ORDER: GridColumnOrder<
-  keyof TransactionSampleRowWithScoreAndExtra
->[] = [
+const SAMPLES_COLUMN_ORDER: GridColumnOrder<keyof TransactionSampleRowWithScore>[] = [
   {key: 'id', width: COL_WIDTH_UNDEFINED, name: 'Event ID'},
   {key: 'user.display', width: COL_WIDTH_UNDEFINED, name: 'User'},
   {key: 'measurements.lcp', width: COL_WIDTH_UNDEFINED, name: 'LCP'},
@@ -71,7 +69,7 @@ const SAMPLES_COLUMN_ORDER: GridColumnOrder<
   {key: 'measurements.ttfb', width: COL_WIDTH_UNDEFINED, name: 'TTFB'},
   {key: 'profile.id', width: COL_WIDTH_UNDEFINED, name: 'Profile'},
   {key: 'replayId', width: COL_WIDTH_UNDEFINED, name: 'Replay'},
-  {key: 'score', width: COL_WIDTH_UNDEFINED, name: 'Score'},
+  {key: 'totalScore', width: COL_WIDTH_UNDEFINED, name: 'Score'},
 ];
 
 function getCurrentTabSelection(selectedTab) {

+ 13 - 9
static/app/views/performance/browser/webVitals/pageOverviewWebVitalsDetailPanel.tsx

@@ -53,7 +53,7 @@ const columnOrder: GridColumnOrder[] = [
 ];
 
 const sort: GridColumnSortBy<keyof TransactionSampleRowWithScore> = {
-  key: 'score',
+  key: 'totalScore',
   order: 'desc',
 };
 
@@ -174,8 +174,8 @@ export function PageOverviewWebVitalsDetailPanel({
     return <NoOverflow>{col.name}</NoOverflow>;
   };
 
-  const getFormattedDuration = (value: number | null) => {
-    if (value === null) {
+  const getFormattedDuration = (value: number) => {
+    if (value === undefined) {
       return null;
     }
     if (value < 1000) {
@@ -188,7 +188,7 @@ export function PageOverviewWebVitalsDetailPanel({
     const {key} = col;
     const projectSlug = getProjectSlug(row);
     if (key === 'score') {
-      if (row[`measurements.${webVital}`] !== null) {
+      if (row[`measurements.${webVital}`] !== undefined) {
         return (
           <AlignCenter>
             <PerformanceBadge score={row[`${webVital}Score`]} />
@@ -198,10 +198,14 @@ export function PageOverviewWebVitalsDetailPanel({
       return null;
     }
     if (col.key === 'webVital') {
-      if (row[key] === null) {
-        return <NoValue>{t('(no value)')}</NoValue>;
-      }
       const value = row[`measurements.${webVital}`];
+      if (value === undefined) {
+        return (
+          <AlignRight>
+            <NoValue>{t('(no value)')}</NoValue>
+          </AlignRight>
+        );
+      }
       const formattedValue =
         webVital === 'cls' ? value?.toFixed(2) : getFormattedDuration(value);
       return <AlignRight>{formattedValue}</AlignRight>;
@@ -217,7 +221,7 @@ export function PageOverviewWebVitalsDetailPanel({
     }
     if (key === 'replayId') {
       const replayTarget =
-        row['transaction.duration'] !== null &&
+        row['transaction.duration'] !== undefined &&
         replayLinkGenerator(
           organization,
           {
@@ -267,7 +271,7 @@ export function PageOverviewWebVitalsDetailPanel({
   return (
     <PageErrorProvider>
       <DetailPanel detailKey={webVital ?? undefined} onClose={onClose}>
-        {webVital && projectData && webVitalScore !== null && (
+        {webVital && projectData && webVitalScore !== undefined && (
           <WebVitalDetailHeader
             value={
               webVital !== 'cls'

+ 39 - 16
static/app/views/performance/browser/webVitals/pagePerformanceTable.tsx

@@ -18,7 +18,7 @@ import {Tooltip} from 'sentry/components/tooltip';
 import {IconChevron} from 'sentry/icons/iconChevron';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
-import {Sort} from 'sentry/utils/discover/fields';
+import {parseFunction, Sort} from 'sentry/utils/discover/fields';
 import {formatAbbreviatedNumber, getDuration} from 'sentry/utils/formatters';
 import {decodeScalar} from 'sentry/utils/queryString';
 import {useLocation} from 'sentry/utils/useLocation';
@@ -32,15 +32,13 @@ import {calculatePerformanceScoreFromStoredTableDataRow} from 'sentry/views/perf
 import {useProjectWebVitalsScoresQuery} from 'sentry/views/performance/browser/webVitals/utils/queries/storedScoreQueries/useProjectWebVitalsScoresQuery';
 import {useTransactionWebVitalsQuery} from 'sentry/views/performance/browser/webVitals/utils/queries/useTransactionWebVitalsQuery';
 import {
-  Row,
+  RowWithScoreAndOpportunity,
   SORTABLE_FIELDS,
   SORTABLE_SCORE_FIELDS,
 } from 'sentry/views/performance/browser/webVitals/utils/types';
 import {useStoredScoresSetting} from 'sentry/views/performance/browser/webVitals/utils/useStoredScoresSetting';
 import {useWebVitalsSort} from 'sentry/views/performance/browser/webVitals/utils/useWebVitalsSort';
 
-type RowWithScoreAndOpportunity = Row & {score: number; opportunity?: number};
-
 type Column = GridColumnHeader<keyof RowWithScoreAndOpportunity>;
 
 const columnOrder: GridColumnOrder<keyof RowWithScoreAndOpportunity>[] = [
@@ -51,7 +49,7 @@ const columnOrder: GridColumnOrder<keyof RowWithScoreAndOpportunity>[] = [
   {key: 'p75(measurements.fid)', width: COL_WIDTH_UNDEFINED, name: 'FID'},
   {key: 'p75(measurements.cls)', width: COL_WIDTH_UNDEFINED, name: 'CLS'},
   {key: 'p75(measurements.ttfb)', width: COL_WIDTH_UNDEFINED, name: 'TTFB'},
-  {key: 'score', width: COL_WIDTH_UNDEFINED, name: 'Score'},
+  {key: 'totalScore', width: COL_WIDTH_UNDEFINED, name: 'Score'},
   {key: 'opportunity', width: COL_WIDTH_UNDEFINED, name: 'Opportunity'},
 ];
 
@@ -98,15 +96,13 @@ export function PagePerformanceTable() {
   const tableData: RowWithScoreAndOpportunity[] = data.map(row => ({
     ...row,
     opportunity: shouldUseStoredScores
-      ? ((row.opportunity ?? 0) * 100) / scoreCount
-      : count !== undefined
-      ? calculateOpportunity(
+      ? (((row as RowWithScoreAndOpportunity).opportunity ?? 0) * 100) / scoreCount
+      : calculateOpportunity(
           projectScore.totalScore ?? 0,
           count,
-          row.score,
+          row.totalScore,
           row['count()']
-        )
-      : undefined,
+        ),
   }));
   const getFormattedDuration = (value: number) => {
     return getDuration(value, value < 1 ? 0 : 2, true);
@@ -115,7 +111,7 @@ export function PagePerformanceTable() {
   function renderHeadCell(col: Column) {
     function generateSortLink() {
       const key =
-        col.key === 'score'
+        col.key === 'totalScore'
           ? 'avg(measurements.score.total)'
           : col.key === 'opportunity'
           ? 'opportunity_score(measurements.score.total)'
@@ -139,7 +135,7 @@ export function PagePerformanceTable() {
       : SORTABLE_FIELDS.filter(field => !SORTABLE_SCORE_FIELDS.includes(field));
     const canSort = (sortableFields as unknown as string[]).includes(col.key);
 
-    if (canSort && !['score', 'opportunity'].includes(col.key)) {
+    if (canSort && !['totalScore', 'opportunity'].includes(col.key)) {
       return (
         <SortLink
           align="right"
@@ -150,7 +146,7 @@ export function PagePerformanceTable() {
         />
       );
     }
-    if (col.key === 'score') {
+    if (col.key === 'totalScore') {
       return (
         <SortLink
           title={
@@ -213,10 +209,10 @@ export function PagePerformanceTable() {
 
   function renderBodyCell(col: Column, row: RowWithScoreAndOpportunity) {
     const {key} = col;
-    if (key === 'score') {
+    if (key === 'totalScore') {
       return (
         <AlignCenter>
-          <PerformanceBadge score={row.score} />
+          <PerformanceBadge score={row.totalScore} />
         </AlignCenter>
       );
     }
@@ -264,9 +260,32 @@ export function PagePerformanceTable() {
         'p75(measurements.fid)',
       ].includes(key)
     ) {
+      const measurement = parseFunction(key)?.arguments?.[0];
+      const func = shouldUseStoredScores ? 'count_scores' : 'count_web_vitals';
+      const args = [measurement, ...(shouldUseStoredScores ? [] : ['any'])];
+      const countWebVitalKey = `${func}(${args.join(',')})`;
+      const countWebVital = row[countWebVitalKey];
+      if (measurement === undefined || countWebVital === 0) {
+        return (
+          <AlignRight>
+            <NoValue>{' \u2014 '}</NoValue>
+          </AlignRight>
+        );
+      }
       return <AlignRight>{getFormattedDuration((row[key] as number) / 1000)}</AlignRight>;
     }
     if (key === 'p75(measurements.cls)') {
+      const countWebVitalKey = shouldUseStoredScores
+        ? 'count_scores(measurements.score.cls)'
+        : 'count_web_vitals(measurements.cls, any)';
+      const countWebVital = row[countWebVitalKey];
+      if (countWebVital === 0) {
+        return (
+          <AlignRight>
+            <NoValue>{' \u2014 '}</NoValue>
+          </AlignRight>
+        );
+      }
       return <AlignRight>{Math.round((row[key] as number) * 100) / 100}</AlignRight>;
     }
     if (key === 'opportunity') {
@@ -406,3 +425,7 @@ const StyledTooltip = styled(Tooltip)`
   top: 1px;
   position: relative;
 `;
+
+const NoValue = styled('span')`
+  color: ${p => p.theme.gray300};
+`;

+ 26 - 24
static/app/views/performance/browser/webVitals/pageSamplePerformanceTable.tsx

@@ -37,21 +37,15 @@ import {
   DEFAULT_INDEXED_SORT,
   SORTABLE_INDEXED_FIELDS,
   SORTABLE_INDEXED_SCORE_FIELDS,
-  TransactionSampleRow,
+  TransactionSampleRowWithScore,
 } from 'sentry/views/performance/browser/webVitals/utils/types';
 import {useStoredScoresSetting} from 'sentry/views/performance/browser/webVitals/utils/useStoredScoresSetting';
 import {useWebVitalsSort} from 'sentry/views/performance/browser/webVitals/utils/useWebVitalsSort';
 import {generateReplayLink} from 'sentry/views/performance/transactionSummary/utils';
 
-export type TransactionSampleRowWithScoreAndExtra = TransactionSampleRow & {
-  score: number;
-};
-
-type Column = GridColumnHeader<keyof TransactionSampleRowWithScoreAndExtra>;
+type Column = GridColumnHeader<keyof TransactionSampleRowWithScore>;
 
-export const COLUMN_ORDER: GridColumnOrder<
-  keyof TransactionSampleRowWithScoreAndExtra
->[] = [
+export const COLUMN_ORDER: GridColumnOrder<keyof TransactionSampleRowWithScore>[] = [
   {key: 'user.display', width: COL_WIDTH_UNDEFINED, name: 'User'},
   {key: 'transaction.duration', width: COL_WIDTH_UNDEFINED, name: 'Duration'},
   {key: 'measurements.lcp', width: COL_WIDTH_UNDEFINED, name: 'LCP'},
@@ -59,12 +53,12 @@ export const COLUMN_ORDER: GridColumnOrder<
   {key: 'measurements.fid', width: COL_WIDTH_UNDEFINED, name: 'FID'},
   {key: 'measurements.cls', width: COL_WIDTH_UNDEFINED, name: 'CLS'},
   {key: 'measurements.ttfb', width: COL_WIDTH_UNDEFINED, name: 'TTFB'},
-  {key: 'score', width: COL_WIDTH_UNDEFINED, name: 'Score'},
+  {key: 'totalScore', width: COL_WIDTH_UNDEFINED, name: 'Score'},
 ];
 
 type Props = {
   transaction: string;
-  columnOrder?: GridColumnOrder<keyof TransactionSampleRowWithScoreAndExtra>[];
+  columnOrder?: GridColumnOrder<keyof TransactionSampleRowWithScore>[];
   limit?: number;
   search?: string;
 };
@@ -103,24 +97,24 @@ export function PageSamplePerformanceTable({
 
   // Do 3 queries filtering on LCP to get a spread of good, meh, and poor events
   // We can't query by performance score yet, so we're using LCP as a best estimate
-  const {data, isLoading, pageLinks} = useTransactionSamplesWebVitalsQuery({
+  const {
+    data: tableData,
+    isLoading,
+    pageLinks,
+  } = useTransactionSamplesWebVitalsQuery({
     limit,
     transaction,
     query: search,
     withProfiles: true,
   });
 
-  const tableData: TransactionSampleRowWithScoreAndExtra[] = data.map(row => ({
-    ...row,
-    view: null,
-  }));
   const getFormattedDuration = (value: number) => {
     return getDuration(value, value < 1 ? 0 : 2, true);
   };
 
   function renderHeadCell(col: Column) {
     function generateSortLink() {
-      const key = col.key === 'score' ? 'measurements.score.total' : col.key;
+      const key = col.key === 'totalScore' ? 'measurements.score.total' : col.key;
       let newSortDirection: Sort['kind'] = 'desc';
       if (sort?.field === key) {
         if (sort.kind === 'desc') {
@@ -165,7 +159,7 @@ export function PageSamplePerformanceTable({
         </AlignRight>
       );
     }
-    if (col.key === 'score') {
+    if (col.key === 'totalScore') {
       return (
         <SortLink
           title={
@@ -203,12 +197,12 @@ export function PageSamplePerformanceTable({
     return <span>{col.name}</span>;
   }
 
-  function renderBodyCell(col: Column, row: TransactionSampleRowWithScoreAndExtra) {
+  function renderBodyCell(col: Column, row: TransactionSampleRowWithScore) {
     const {key} = col;
-    if (key === 'score') {
+    if (key === 'totalScore') {
       return (
         <AlignCenter>
-          <PerformanceBadge score={row.score} />
+          <PerformanceBadge score={row.totalScore} />
         </AlignCenter>
       );
     }
@@ -243,7 +237,7 @@ export function PageSamplePerformanceTable({
     ) {
       return (
         <AlignRight>
-          {row[key] === null ? (
+          {row[key] === undefined ? (
             <NoValue>{' \u2014 '}</NoValue>
           ) : (
             getFormattedDuration((row[key] as number) / 1000)
@@ -252,7 +246,15 @@ export function PageSamplePerformanceTable({
       );
     }
     if (['measurements.cls', 'opportunity'].includes(key)) {
-      return <AlignRight>{Math.round((row[key] as number) * 100) / 100}</AlignRight>;
+      return (
+        <AlignRight>
+          {row[key] === undefined ? (
+            <NoValue>{' \u2014 '}</NoValue>
+          ) : (
+            Math.round((row[key] as number) * 100) / 100
+          )}
+        </AlignRight>
+      );
     }
     if (key === 'profile.id') {
       const profileTarget =
@@ -280,7 +282,7 @@ export function PageSamplePerformanceTable({
 
     if (key === 'replayId') {
       const replayTarget =
-        row['transaction.duration'] !== null &&
+        row['transaction.duration'] !== undefined &&
         replayLinkGenerator(
           organization,
           {

+ 14 - 33
static/app/views/performance/browser/webVitals/performanceScoreChart.tsx

@@ -9,8 +9,10 @@ import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 import usePageFilters from 'sentry/utils/usePageFilters';
 import {PerformanceScoreBreakdownChart} from 'sentry/views/performance/browser/webVitals/components/performanceScoreBreakdownChart';
-import {ProjectScore} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/calculatePerformanceScore';
-import {WebVitals} from 'sentry/views/performance/browser/webVitals/utils/types';
+import {
+  ProjectScore,
+  WebVitals,
+} from 'sentry/views/performance/browser/webVitals/utils/types';
 
 import PerformanceScoreRingWithTooltips from './components/performanceScoreRingWithTooltips';
 
@@ -19,9 +21,6 @@ type Props = {
   projectScore?: ProjectScore;
   transaction?: string;
   webVital?: WebVitals | null;
-  weights?: {
-    [key in WebVitals]: number;
-  };
 };
 
 export const ORDER = ['lcp', 'fcp', 'fid', 'cls', 'ttfb'];
@@ -57,34 +56,16 @@ export function PerformanceScoreChart({
   const period = pageFilters.selection.datetime.period;
   const performanceScoreSubtext = (period && DEFAULT_RELATIVE_PERIODS[period]) ?? '';
 
-  const containsWeights = (
-    weights: ProjectScore
-  ): weights is ProjectScore & {
-    clsWeight: number;
-    fcpWeight: number;
-    fidWeight: number;
-    lcpWeight: number;
-    ttfbWeight: number;
-  } => {
-    return !!(
-      weights?.clsWeight &&
-      weights?.fcpWeight &&
-      weights?.fidWeight &&
-      weights?.lcpWeight &&
-      weights?.ttfbWeight
-    );
-  };
-
-  const weights =
-    projectScore && containsWeights(projectScore)
-      ? {
-          cls: projectScore.clsWeight,
-          fcp: projectScore.fcpWeight,
-          fid: projectScore.fidWeight,
-          lcp: projectScore.lcpWeight,
-          ttfb: projectScore.ttfbWeight,
-        }
-      : undefined;
+  // Gets weights to dynamically size the performance score ring segments
+  const weights = projectScore
+    ? {
+        cls: projectScore.clsWeight,
+        fcp: projectScore.fcpWeight,
+        fid: projectScore.fidWeight,
+        lcp: projectScore.lcpWeight,
+        ttfb: projectScore.ttfbWeight,
+      }
+    : undefined;
 
   return (
     <Flex>

+ 8 - 7
static/app/views/performance/browser/webVitals/utils/getWebVitalValues.tsx

@@ -1,8 +1,9 @@
 import {TableDataRow} from 'sentry/utils/discover/discoverQuery';
+import {Vitals} from 'sentry/views/performance/browser/webVitals/utils/queries/rawWebVitalsQueries/calculatePerformanceScore';
 import {WebVitals} from 'sentry/views/performance/browser/webVitals/utils/types';
 
 function hasWebVital(data: TableDataRow, webVital: WebVitals): boolean {
-  if (Object.keys(data).includes(`count_web_vitals(measurements.${webVital}, any)`)) {
+  if (data.hasOwnProperty(`count_web_vitals(measurements.${webVital}, any)`)) {
     return (data[`count_web_vitals(measurements.${webVital}, any)`] as number) > 0;
   }
   return false;
@@ -12,7 +13,7 @@ function getWebVital(data: TableDataRow, webVital: WebVitals): number {
   return data[`p75(measurements.${webVital})`] as number;
 }
 
-export function getWebVitalsFromTableData(data: TableDataRow) {
+export function getWebVitalsFromTableData(data: TableDataRow): Vitals {
   const hasLcp = hasWebVital(data, 'lcp');
   const hasFcp = hasWebVital(data, 'fcp');
   const hasCls = hasWebVital(data, 'cls');
@@ -20,10 +21,10 @@ export function getWebVitalsFromTableData(data: TableDataRow) {
   const hasTtfb = hasWebVital(data, 'ttfb');
 
   return {
-    lcp: hasLcp ? getWebVital(data, 'lcp') : null,
-    fcp: hasFcp ? getWebVital(data, 'fcp') : null,
-    cls: hasCls ? getWebVital(data, 'cls') : null,
-    ttfb: hasTtfb ? getWebVital(data, 'ttfb') : null,
-    fid: hasFid ? getWebVital(data, 'fid') : null,
+    lcp: hasLcp ? getWebVital(data, 'lcp') : undefined,
+    fcp: hasFcp ? getWebVital(data, 'fcp') : undefined,
+    cls: hasCls ? getWebVital(data, 'cls') : undefined,
+    ttfb: hasTtfb ? getWebVital(data, 'ttfb') : undefined,
+    fid: hasFid ? getWebVital(data, 'fid') : undefined,
   };
 }

Some files were not shown because too many files changed in this diff