Browse Source

feat(replays): add ui.tap breadcrumb (#70189)

tested that it renders correctly on this replay with the new type
`ui.tap` being sent in. this new type closely mirrors the `ui.click`
definition

<img width="956" alt="SCR-20240503-jhux"
src="https://github.com/getsentry/sentry/assets/56095982/fbc6b4b8-f2ca-4f26-bb16-f5eb8228439c">



closes https://github.com/getsentry/sentry/issues/69253
Michelle Zhang 10 months ago
parent
commit
d167b1b42b

+ 8 - 0
static/app/utils/replays/getFrameDetails.tsx

@@ -32,6 +32,7 @@ import type {
   NavFrame,
   ReplayFrame,
   SlowClickFrame,
+  TapFrame,
 } from 'sentry/utils/replays/types';
 import {
   getFrameOpOrCategory,
@@ -184,6 +185,13 @@ const MAPPER_FOR_FRAME: Record<string, (frame) => Details> = {
     title: 'User Click',
     icon: <IconCursorArrow size="xs" />,
   }),
+  'ui.tap': (frame: TapFrame) => ({
+    color: 'blue300',
+    description: frame.message,
+    tabKey: TabKey.BREADCRUMBS,
+    title: 'User Tap',
+    icon: <IconUser size="xs" />,
+  }),
   'ui.input': () => ({
     color: 'blue300',
     description: 'User Action',

+ 1 - 1
static/app/utils/replays/replayReader.tsx

@@ -480,7 +480,7 @@ export default class ReplayReader {
     const crumbs = removeDuplicateClicks(
       this._sortedBreadcrumbFrames.filter(
         frame =>
-          ['navigation', 'ui.click'].includes(frame.category) ||
+          ['navigation', 'ui.click', 'ui.tap'].includes(frame.category) ||
           (frame.category === 'ui.slowClickDetected' &&
             (isDeadClick(frame as SlowClickFrame) ||
               isDeadRageClick(frame as SlowClickFrame)))

+ 25 - 10
static/app/utils/replays/types.tsx

@@ -17,20 +17,32 @@ import invariant from 'invariant';
 
 import type {HydratedA11yFrame} from 'sentry/utils/replays/hydrateA11yFrame';
 
-/**
- * Extra breadcrumb types not included in `@sentry/replay`
- */
-type ExtraBreadcrumbTypes = {
-  category: 'navigation';
-  data: {
-    from: string;
-    to: string;
-  };
+// TODO: more types get added here
+type MobileBreadcrumbTypes = {
+  category: 'ui.tap';
+  data: any;
   message: string;
   timestamp: number;
-  type: string; // For compatibility reasons
+  type: string;
 };
 
+/**
+ * Extra breadcrumb types not included in `@sentry/replay`
+ * Also includes mobile types
+ */
+type ExtraBreadcrumbTypes =
+  | MobileBreadcrumbTypes
+  | {
+      category: 'navigation';
+      data: {
+        from: string;
+        to: string;
+      };
+      message: string;
+      timestamp: number;
+      type: string; // For compatibility reasons
+    };
+
 export type RawBreadcrumbFrame = TRawBreadcrumbFrame | ExtraBreadcrumbTypes;
 export type BreadcrumbFrameEvent = TBreadcrumbFrameEvent;
 export type RecordingFrame = TEventWithTime;
@@ -148,6 +160,7 @@ type HydratedTimestamp = {
    */
   timestampMs: number;
 };
+
 type HydratedBreadcrumb<Category extends string> = Overwrite<
   Extract<TRawBreadcrumbFrame | ExtraBreadcrumbTypes, {category: Category}>,
   HydratedTimestamp
@@ -209,6 +222,7 @@ export type FeedbackFrame = {
 
 export type BlurFrame = HydratedBreadcrumb<'ui.blur'>;
 export type ClickFrame = HydratedBreadcrumb<'ui.click'>;
+export type TapFrame = HydratedBreadcrumb<'ui.tap'>;
 export type ConsoleFrame = HydratedBreadcrumb<'console'>;
 export type FocusFrame = HydratedBreadcrumb<'ui.focus'>;
 export type InputFrame = HydratedBreadcrumb<'ui.input'>;
@@ -228,6 +242,7 @@ export const BreadcrumbCategories = [
   'replay.hydrate-error',
   'ui.blur',
   'ui.click',
+  'ui.tap',
   'ui.focus',
   'ui.input',
   'ui.keyDown',

+ 2 - 0
static/app/views/replays/detail/breadcrumbs/useBreadcrumbFilters.tsx

@@ -49,6 +49,7 @@ const TYPE_TO_LABEL: Record<string, string> = {
   click: 'User Click',
   keydown: 'KeyDown',
   input: 'Input',
+  tap: 'User Tap',
 };
 
 const OPORCATEGORY_TO_TYPE: Record<string, keyof typeof TYPE_TO_LABEL> = {
@@ -70,6 +71,7 @@ const OPORCATEGORY_TO_TYPE: Record<string, keyof typeof TYPE_TO_LABEL> = {
   'replay.hydrate-error': 'hydrateError',
   'largest-contentful-paint': 'lcp',
   'ui.click': 'click',
+  'ui.tap': 'tap',
   'ui.keyDown': 'keydown',
   'ui.input': 'input',
   feedback: 'feedback',