Browse Source

feat(mobile-vitals): Add optional stall percentage vital card (#27586)

This change adds an optionl vital card for the stall percentage that will only
be shown when there is data.
Tony Xiao 3 years ago
parent
commit
809b7fe54c

+ 5 - 0
static/app/views/performance/data.tsx

@@ -48,6 +48,7 @@ export enum PERFORMANCE_TERM {
   APP_START_WARM = 'appStartWarm',
   SLOW_FRAMES = 'slowFrames',
   FROZEN_FRAMES = 'frozenFrames',
+  STALL_PERCENTAGE = 'stallPercentage',
 }
 
 export type TooltipOption = SelectValue<string> & {
@@ -384,6 +385,10 @@ const PERFORMANCE_TERMS: Record<PERFORMANCE_TERM, TermFormatter> = {
     t('Warm start is a measure of the application start up time while still in memory.'),
   slowFrames: () => t('The count of the number of slow frames in the transaction.'),
   frozenFrames: () => t('The count of the number of frozen frames in the transaction.'),
+  stallPercentage: () =>
+    t(
+      'The percentage of the transaction duration in which the application is in a stalled state.'
+    ),
 };
 
 export function getTermHelp(

+ 5 - 0
static/app/views/performance/landing/utils.tsx

@@ -157,6 +157,11 @@ export const vitalCardDetails = (
       tooltip: getTermHelp(organization, PERFORMANCE_TERM.APP_START_WARM),
       formatter: value => getDuration(value / 1000, value >= 1000 ? 3 : 0, true),
     },
+    'p75(measurements.stall_percentage)': {
+      title: t('Stall Percentage (p75)'),
+      tooltip: getTermHelp(organization, PERFORMANCE_TERM.STALL_PERCENTAGE),
+      formatter: value => formatPercentage(value, 2),
+    },
   };
 };
 

+ 26 - 4
static/app/views/performance/landing/vitalsCards.tsx

@@ -18,10 +18,16 @@ import {t} from 'app/locale';
 import overflowEllipsis from 'app/styles/overflowEllipsis';
 import space from 'app/styles/space';
 import {Organization, Project} from 'app/types';
+import {defined} from 'app/utils';
 import {getUtcToLocalDateObject} from 'app/utils/dates';
 import DiscoverQuery from 'app/utils/discover/discoverQuery';
 import EventView from 'app/utils/discover/eventView';
-import {Column, getAggregateAlias, WebVital} from 'app/utils/discover/fields';
+import {
+  Column,
+  generateFieldAsString,
+  getAggregateAlias,
+  WebVital,
+} from 'app/utils/discover/fields';
 import {WEB_VITAL_DETAILS} from 'app/utils/performance/vitals/constants';
 import VitalsCardsDiscoverQuery, {
   VitalData,
@@ -130,8 +136,12 @@ type BaseCardsProps = {
   organization: Organization;
 };
 
+type OptionalColumn = Column & {
+  optional?: boolean;
+};
+
 type GenericCardsProps = BaseCardsProps & {
-  functions: Column[];
+  functions: OptionalColumn[];
 };
 
 function GenericCards(props: GenericCardsProps) {
@@ -185,7 +195,9 @@ function GenericCards(props: GenericCardsProps) {
 
             return (
               <VitalsContainer>
-                {eventView.getFields().map(fieldName => {
+                {functions.map(func => {
+                  let fieldName = generateFieldAsString(func);
+
                   if (fieldName.includes('apdex')) {
                     // Replace apdex with explicit thresholds with a generic one for lookup
                     fieldName = 'apdex()';
@@ -200,6 +212,11 @@ function GenericCards(props: GenericCardsProps) {
                   const {title, tooltip, formatter} = cardDetail;
                   const alias = getAggregateAlias(fieldName);
                   const rawValue = tableData?.data?.[0]?.[alias];
+
+                  if (func.optional && !defined(rawValue)) {
+                    return null;
+                  }
+
                   const data = series?.[fieldName];
                   const value =
                     isSummaryLoading || rawValue === undefined
@@ -253,7 +270,7 @@ function _BackendCards(props: BaseCardsProps) {
 export const BackendCards = withApi(_BackendCards);
 
 function _MobileCards(props: BaseCardsProps) {
-  const functions: Column[] = [
+  const functions: OptionalColumn[] = [
     {
       kind: 'function',
       function: ['p75', 'measurements.app_start_cold', undefined, undefined],
@@ -270,6 +287,11 @@ function _MobileCards(props: BaseCardsProps) {
       kind: 'function',
       function: ['p75', 'measurements.frames_frozen_rate', undefined, undefined],
     },
+    {
+      kind: 'function',
+      function: ['p75', 'measurements.stall_percentage', undefined, undefined],
+      optional: true,
+    },
   ];
   return <GenericCards {...props} functions={functions} />;
 }