Browse Source

feat(mobile-starfish): Replace release labels with R1, R2 (#64408)

In order to simplify the text being shown in headers, we've decided to
modify the release selector to prefix the primary release with "R1" and
the secondary release with "R2" and update usages in the table headers
and metrics ribbon to fit this abbreviation

Updated both the app start module as well as the screen loads
module to be consistent since they share the release selector and both
modules will need this change eventually.
Nar Saynorath 1 year ago
parent
commit
47d14fca6f

+ 13 - 4
static/app/views/starfish/components/releaseSelector.tsx

@@ -19,13 +19,17 @@ import {
 } from 'sentry/views/starfish/queries/useReleases';
 import {formatVersionAndCenterTruncate} from 'sentry/views/starfish/utils/centerTruncate';
 
+export const PRIMARY_RELEASE_ALIAS = 'R1';
+export const SECONDARY_RELEASE_ALIAS = 'R2';
+
 type Props = {
   selectorKey: string;
   selectorName?: string;
   selectorValue?: string;
+  triggerLabelPrefix?: string;
 };
 
-export function ReleaseSelector({selectorKey, selectorValue}: Props) {
+export function ReleaseSelector({selectorKey, selectorValue, triggerLabelPrefix}: Props) {
   const [searchTerm, setSearchTerm] = useState<string | undefined>(undefined);
   const {data, isLoading} = useReleases(searchTerm);
   const {primaryRelease, secondaryRelease} = useReleaseSelection();
@@ -66,15 +70,18 @@ export function ReleaseSelector({selectorKey, selectorValue}: Props) {
       options.push(option);
     });
 
+  const triggerLabelContent = selectorValue
+    ? formatVersionAndCenterTruncate(selectorValue, 16)
+    : selectorValue;
+
   return (
     <StyledCompactSelect
       triggerProps={{
         icon: <IconReleases />,
         title: selectorValue,
+        prefix: triggerLabelPrefix,
       }}
-      triggerLabel={
-        selectorValue ? formatVersionAndCenterTruncate(selectorValue, 16) : selectorValue
-      }
+      triggerLabel={triggerLabelContent}
       menuTitle={t('Filter Release')}
       loading={isLoading}
       searchable
@@ -136,12 +143,14 @@ export function ReleaseComparisonSelector() {
         selectorValue={primaryRelease}
         selectorName={t('Release 1')}
         key="primaryRelease"
+        triggerLabelPrefix={PRIMARY_RELEASE_ALIAS}
       />
       <ReleaseSelector
         selectorKey="secondaryRelease"
         selectorName={t('Release 2')}
         selectorValue={secondaryRelease}
         key="secondaryRelease"
+        triggerLabelPrefix={SECONDARY_RELEASE_ALIAS}
       />
     </StyledPageSelector>
   );

+ 23 - 3
static/app/views/starfish/views/appStartup/screenSummary/eventSamples.spec.tsx

@@ -4,6 +4,7 @@ import {ProjectFixture} from 'sentry-fixture/project';
 import {render, screen} from 'sentry-test/reactTestingLibrary';
 
 import usePageFilters from 'sentry/utils/usePageFilters';
+import {useReleaseSelection} from 'sentry/views/starfish/queries/useReleases';
 import {EventSamples} from 'sentry/views/starfish/views/appStartup/screenSummary/eventSamples';
 import {
   MobileCursors,
@@ -11,6 +12,7 @@ import {
 } from 'sentry/views/starfish/views/screens/constants';
 
 jest.mock('sentry/utils/usePageFilters');
+jest.mock('sentry/views/starfish/queries/useReleases');
 
 describe('ScreenLoadEventSamples', function () {
   const organization = OrganizationFixture();
@@ -34,6 +36,26 @@ describe('ScreenLoadEventSamples', function () {
         projects: [parseInt(project.id, 10)],
       },
     });
+    jest.mocked(useReleaseSelection).mockReturnValue({
+      primaryRelease: 'com.example.vu.android@2.10.5',
+      isLoading: false,
+      secondaryRelease: 'com.example.vu.android@2.10.3+42',
+    });
+    MockApiClient.addMockResponse({
+      url: `/organizations/${organization.slug}/releases/`,
+      body: [
+        {
+          id: 970136705,
+          version: 'com.example.vu.android@2.10.5',
+          dateCreated: '2023-12-19T21:37:53.895495Z',
+        },
+        {
+          id: 969902997,
+          version: 'com.example.vu.android@2.10.3+42',
+          dateCreated: '2023-12-19T18:04:06.953025Z',
+        },
+      ],
+    });
     mockEventsRequest = MockApiClient.addMockResponse({
       url: `/organizations/${organization.slug}/events/`,
       body: {
@@ -73,9 +95,7 @@ describe('ScreenLoadEventSamples', function () {
     );
 
     // Check that headers are set properly
-    expect(
-      screen.getByRole('columnheader', {name: 'Event ID (2.10.5)'})
-    ).toBeInTheDocument();
+    expect(screen.getByRole('columnheader', {name: 'Event ID (R1)'})).toBeInTheDocument();
     expect(screen.getByRole('columnheader', {name: 'Profile'})).toBeInTheDocument();
     expect(screen.getByRole('columnheader', {name: 'Start Type'})).toBeInTheDocument();
     expect(screen.getByRole('columnheader', {name: 'Duration'})).toBeInTheDocument();

+ 10 - 2
static/app/views/starfish/views/appStartup/screenSummary/eventSamples.tsx

@@ -7,7 +7,11 @@ import {decodeScalar} from 'sentry/utils/queryString';
 import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import {useLocation} from 'sentry/utils/useLocation';
 import usePageFilters from 'sentry/utils/usePageFilters';
-import {formatVersionAndCenterTruncate} from 'sentry/views/starfish/utils/centerTruncate';
+import {
+  PRIMARY_RELEASE_ALIAS,
+  SECONDARY_RELEASE_ALIAS,
+} from 'sentry/views/starfish/components/releaseSelector';
+import {useReleaseSelection} from 'sentry/views/starfish/queries/useReleases';
 import {EventSamplesTable} from 'sentry/views/starfish/views/screens/screenLoadSpans/eventSamplesTable';
 import {useTableQuery} from 'sentry/views/starfish/views/screens/screensTable';
 
@@ -33,6 +37,7 @@ export function EventSamples({
 }: Props) {
   const location = useLocation();
   const {selection} = usePageFilters();
+  const {primaryRelease} = useReleaseSelection();
   const cursor = decodeScalar(location.query?.[cursorName]);
 
   const searchQuery = new MutableSearch([
@@ -59,7 +64,10 @@ export function EventSamples({
   const sort = fromSorts(decodeScalar(location.query[sortKey]))[0] ?? DEFAULT_SORT;
 
   const columnNameMap = {
-    'transaction.id': t('Event ID (%s)', formatVersionAndCenterTruncate(release)),
+    'transaction.id': t(
+      'Event ID (%s)',
+      release === primaryRelease ? PRIMARY_RELEASE_ALIAS : SECONDARY_RELEASE_ALIAS
+    ),
     profile_id: t('Profile'),
     'span.description': t('Start Type'),
     'span.duration': t('Duration'),

+ 4 - 4
static/app/views/starfish/views/appStartup/screenSummary/index.spec.tsx

@@ -110,10 +110,10 @@ describe('Screen Summary', function () {
       });
 
       const blocks = [
-        {header: 'Cold Start (2.10.5)', value: '1.00s'},
-        {header: 'Cold Start (2.10.… (42))', value: '2.00s'},
-        {header: 'Warm Start (2.10.5)', value: '5.00s'},
-        {header: 'Warm Start (2.10.… (42))', value: '6.00s'},
+        {header: 'Cold Start (R1)', value: '1.00s'},
+        {header: 'Cold Start (R2)', value: '2.00s'},
+        {header: 'Warm Start (R1)', value: '5.00s'},
+        {header: 'Warm Start (R2)', value: '6.00s'},
         {header: 'Count', value: '50'},
       ];
 

+ 9 - 9
static/app/views/starfish/views/appStartup/screenSummary/index.tsx

@@ -17,9 +17,12 @@ import {PageAlert, PageAlertProvider} from 'sentry/utils/performance/contexts/pa
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 import useRouter from 'sentry/utils/useRouter';
-import {ReleaseComparisonSelector} from 'sentry/views/starfish/components/releaseSelector';
+import {
+  PRIMARY_RELEASE_ALIAS,
+  ReleaseComparisonSelector,
+  SECONDARY_RELEASE_ALIAS,
+} from 'sentry/views/starfish/components/releaseSelector';
 import {SpanMetricsField} from 'sentry/views/starfish/types';
-import {formatVersionAndCenterTruncate} from 'sentry/views/starfish/utils/centerTruncate';
 import {EventSamples} from 'sentry/views/starfish/views/appStartup/screenSummary/eventSamples';
 import {SpanOperationTable} from 'sentry/views/starfish/views/appStartup/screenSummary/spanOperationTable';
 import {QueryParameterNames} from 'sentry/views/starfish/views/queryParameters';
@@ -79,9 +82,6 @@ function ScreenSummary() {
     },
   ];
 
-  const truncatedPrimary = formatVersionAndCenterTruncate(primaryRelease ?? '', 10);
-  const truncatedSecondary = formatVersionAndCenterTruncate(secondaryRelease ?? '', 10);
-
   return (
     <SentryDocumentTitle title={transactionName} orgSlug={organization.slug}>
       <Layout.Page>
@@ -122,7 +122,7 @@ function ScreenSummary() {
                     blocks={[
                       {
                         type: 'duration',
-                        title: t('Cold Start (%s)', truncatedPrimary),
+                        title: t('Cold Start (%s)', PRIMARY_RELEASE_ALIAS),
                         dataKey: data => {
                           const matchingRow = data?.find(
                             row => row['span.op'] === 'app.start.cold'
@@ -136,7 +136,7 @@ function ScreenSummary() {
                       },
                       {
                         type: 'duration',
-                        title: t('Cold Start (%s)', truncatedSecondary),
+                        title: t('Cold Start (%s)', SECONDARY_RELEASE_ALIAS),
                         dataKey: data => {
                           const matchingRow = data?.find(
                             row => row['span.op'] === 'app.start.cold'
@@ -150,7 +150,7 @@ function ScreenSummary() {
                       },
                       {
                         type: 'duration',
-                        title: t('Warm Start (%s)', truncatedPrimary),
+                        title: t('Warm Start (%s)', PRIMARY_RELEASE_ALIAS),
                         dataKey: data => {
                           const matchingRow = data?.find(
                             row => row['span.op'] === 'app.start.warm'
@@ -164,7 +164,7 @@ function ScreenSummary() {
                       },
                       {
                         type: 'duration',
-                        title: t('Warm Start (%s)', truncatedSecondary),
+                        title: t('Warm Start (%s)', SECONDARY_RELEASE_ALIAS),
                         dataKey: data => {
                           const matchingRow = data?.find(
                             row => row['span.op'] === 'app.start.warm'

+ 2 - 2
static/app/views/starfish/views/appStartup/screenSummary/spanOperationTable.spec.tsx

@@ -82,8 +82,8 @@ describe('SpanOpSelector', function () {
 
     expect(await screen.findByRole('link', {name: 'Operation'})).toBeInTheDocument();
     expect(screen.getByRole('link', {name: 'Span Description'})).toBeInTheDocument();
-    expect(screen.getByRole('link', {name: 'Duration (release1)'})).toBeInTheDocument();
-    expect(screen.getByRole('link', {name: 'Duration (release2)'})).toBeInTheDocument();
+    expect(screen.getByRole('link', {name: 'Duration (R1)'})).toBeInTheDocument();
+    expect(screen.getByRole('link', {name: 'Duration (R2)'})).toBeInTheDocument();
     expect(screen.getByRole('link', {name: 'Total Count'})).toBeInTheDocument();
     expect(screen.getByRole('link', {name: 'Total Time Spent'})).toBeInTheDocument();
 

+ 6 - 5
static/app/views/starfish/views/appStartup/screenSummary/spanOperationTable.tsx

@@ -24,9 +24,12 @@ import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 import usePageFilters from 'sentry/utils/usePageFilters';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
+import {
+  PRIMARY_RELEASE_ALIAS,
+  SECONDARY_RELEASE_ALIAS,
+} from 'sentry/views/starfish/components/releaseSelector';
 import {OverflowEllipsisTextContainer} from 'sentry/views/starfish/components/textAlign';
 import {SpanMetricsField} from 'sentry/views/starfish/types';
-import {formatVersionAndCenterTruncate} from 'sentry/views/starfish/utils/centerTruncate';
 import {STARFISH_CHART_INTERVAL_FIDELITY} from 'sentry/views/starfish/utils/constants';
 import {appendReleaseFilters} from 'sentry/views/starfish/utils/releaseComparison';
 import {SpanOpSelector} from 'sentry/views/starfish/views/appStartup/screenSummary/spanOpSelector';
@@ -64,8 +67,6 @@ export function SpanOperationTable({
   const cursor = decodeScalar(location.query?.[MobileCursors.SPANS_TABLE]);
 
   const spanOp = decodeScalar(location.query[SpanMetricsField.SPAN_OP]) ?? '';
-  const truncatedPrimary = formatVersionAndCenterTruncate(primaryRelease ?? '', 15);
-  const truncatedSecondary = formatVersionAndCenterTruncate(secondaryRelease ?? '', 15);
 
   const searchQuery = new MutableSearch([
     'transaction.op:ui.load',
@@ -127,11 +128,11 @@ export function SpanOperationTable({
     'count()': t('Total Count'),
     [`avg_if(${SPAN_SELF_TIME},release,${primaryRelease})`]: t(
       'Duration (%s)',
-      truncatedPrimary
+      PRIMARY_RELEASE_ALIAS
     ),
     [`avg_if(${SPAN_SELF_TIME},release,${secondaryRelease})`]: t(
       'Duration (%s)',
-      truncatedSecondary
+      SECONDARY_RELEASE_ALIAS
     ),
     ['time_spent_percentage()']: t('Total Time Spent'),
   };

+ 8 - 15
static/app/views/starfish/views/appStartup/screensTable.tsx

@@ -18,13 +18,14 @@ import useOrganization from 'sentry/utils/useOrganization';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
 import TopResultsIndicator from 'sentry/views/discover/table/topResultsIndicator';
 import {COLD_START_COLOR, WARM_START_COLOR} from 'sentry/views/starfish/colours';
+import {
+  PRIMARY_RELEASE_ALIAS,
+  SECONDARY_RELEASE_ALIAS,
+} from 'sentry/views/starfish/components/releaseSelector';
 import {useReleaseSelection} from 'sentry/views/starfish/queries/useReleases';
-import {formatVersionAndCenterTruncate} from 'sentry/views/starfish/utils/centerTruncate';
 import Breakdown from 'sentry/views/starfish/views/appStartup/breakdown';
 import {TOP_SCREENS} from 'sentry/views/starfish/views/screens';
 
-const MAX_TABLE_RELEASE_CHARS = 15;
-
 type Props = {
   data: TableData | undefined;
   eventView: EventView;
@@ -36,32 +37,24 @@ export function ScreensTable({data, eventView, isLoading, pageLinks}: Props) {
   const location = useLocation();
   const organization = useOrganization();
   const {primaryRelease, secondaryRelease} = useReleaseSelection();
-  const truncatedPrimary = formatVersionAndCenterTruncate(
-    primaryRelease ?? '',
-    MAX_TABLE_RELEASE_CHARS
-  );
-  const truncatedSecondary = formatVersionAndCenterTruncate(
-    secondaryRelease ?? '',
-    MAX_TABLE_RELEASE_CHARS
-  );
 
   const columnNameMap = {
     transaction: t('Screen'),
     [`avg_if(measurements.app_start_cold,release,${primaryRelease})`]: t(
       'Cold Start (%s)',
-      truncatedPrimary
+      PRIMARY_RELEASE_ALIAS
     ),
     [`avg_if(measurements.app_start_cold,release,${secondaryRelease})`]: t(
       'Cold Start (%s)',
-      truncatedSecondary
+      SECONDARY_RELEASE_ALIAS
     ),
     [`avg_if(measurements.app_start_warm,release,${primaryRelease})`]: t(
       'Warm Start (%s)',
-      truncatedPrimary
+      PRIMARY_RELEASE_ALIAS
     ),
     [`avg_if(measurements.app_start_warm,release,${secondaryRelease})`]: t(
       'Warm Start (%s)',
-      truncatedSecondary
+      SECONDARY_RELEASE_ALIAS
     ),
     app_start_breakdown: t('App Start Breakdown'),
     'count()': t('Total Count'),

+ 23 - 3
static/app/views/starfish/views/screens/screenLoadSpans/eventSamples.spec.tsx

@@ -4,6 +4,7 @@ import {ProjectFixture} from 'sentry-fixture/project';
 import {render, screen} from 'sentry-test/reactTestingLibrary';
 
 import usePageFilters from 'sentry/utils/usePageFilters';
+import {useReleaseSelection} from 'sentry/views/starfish/queries/useReleases';
 import {
   MobileCursors,
   MobileSortKeys,
@@ -11,6 +12,7 @@ import {
 import {ScreenLoadEventSamples} from 'sentry/views/starfish/views/screens/screenLoadSpans/eventSamples';
 
 jest.mock('sentry/utils/usePageFilters');
+jest.mock('sentry/views/starfish/queries/useReleases');
 
 describe('ScreenLoadEventSamples', function () {
   const organization = OrganizationFixture();
@@ -34,6 +36,26 @@ describe('ScreenLoadEventSamples', function () {
         projects: [parseInt(project.id, 10)],
       },
     });
+    jest.mocked(useReleaseSelection).mockReturnValue({
+      primaryRelease: 'com.example.vu.android@2.10.5',
+      isLoading: false,
+      secondaryRelease: 'com.example.vu.android@2.10.3+42',
+    });
+    MockApiClient.addMockResponse({
+      url: `/organizations/${organization.slug}/releases/`,
+      body: [
+        {
+          id: 970136705,
+          version: 'com.example.vu.android@2.10.5',
+          dateCreated: '2023-12-19T21:37:53.895495Z',
+        },
+        {
+          id: 969902997,
+          version: 'com.example.vu.android@2.10.3+42',
+          dateCreated: '2023-12-19T18:04:06.953025Z',
+        },
+      ],
+    });
     mockEventsRequest = MockApiClient.addMockResponse({
       url: `/organizations/${organization.slug}/events/`,
       body: {
@@ -71,9 +93,7 @@ describe('ScreenLoadEventSamples', function () {
     );
 
     // Check that headers are set properly
-    expect(
-      screen.getByRole('columnheader', {name: 'Event ID (2.10.5)'})
-    ).toBeInTheDocument();
+    expect(screen.getByRole('columnheader', {name: 'Event ID (R1)'})).toBeInTheDocument();
     expect(screen.getByRole('columnheader', {name: 'Profile'})).toBeInTheDocument();
     expect(screen.getByRole('columnheader', {name: 'TTID'})).toBeInTheDocument();
     expect(screen.getByRole('columnheader', {name: 'TTFD'})).toBeInTheDocument();

+ 10 - 2
static/app/views/starfish/views/screens/screenLoadSpans/eventSamples.tsx

@@ -9,7 +9,11 @@ import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 import usePageFilters from 'sentry/utils/usePageFilters';
-import {formatVersionAndCenterTruncate} from 'sentry/views/starfish/utils/centerTruncate';
+import {
+  PRIMARY_RELEASE_ALIAS,
+  SECONDARY_RELEASE_ALIAS,
+} from 'sentry/views/starfish/components/releaseSelector';
+import {useReleaseSelection} from 'sentry/views/starfish/queries/useReleases';
 import {
   DEFAULT_PLATFORM,
   PLATFORM_LOCAL_STORAGE_KEY,
@@ -44,6 +48,7 @@ export function ScreenLoadEventSamples({
   const location = useLocation();
   const {selection} = usePageFilters();
   const organization = useOrganization();
+  const {primaryRelease} = useReleaseSelection();
   const cursor = decodeScalar(location.query?.[cursorName]);
 
   const deviceClass = decodeScalar(location.query['device.class']);
@@ -81,7 +86,10 @@ export function ScreenLoadEventSamples({
   const sort = fromSorts(decodeScalar(location.query[sortKey]))[0] ?? DEFAULT_SORT;
 
   const columnNameMap = {
-    id: t('Event ID (%s)', formatVersionAndCenterTruncate(release)),
+    id: t(
+      'Event ID (%s)',
+      release === primaryRelease ? PRIMARY_RELEASE_ALIAS : SECONDARY_RELEASE_ALIAS
+    ),
     'profile.id': t('Profile'),
     'measurements.time_to_initial_display': t('TTID'),
     'measurements.time_to_full_display': t('TTFD'),

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