diff --git a/static/app/components/events/contexts/knownContext/accessibility.spec.tsx b/static/app/components/events/contexts/knownContext/accessibility.spec.tsx new file mode 100644 index 000000000000..49e9835858f7 --- /dev/null +++ b/static/app/components/events/contexts/knownContext/accessibility.spec.tsx @@ -0,0 +1,79 @@ +import {EventFixture} from 'sentry-fixture/event'; + +import {render, screen} from 'sentry-test/reactTestingLibrary'; + +import {ContextCard} from 'sentry/components/events/contexts/contextCard'; +import { + getAccessibilityContextData, + type AccessibilityContext, +} from 'sentry/components/events/contexts/knownContext/accessibility'; + +const MOCK_ACCESSIBILITY_CONTEXT: AccessibilityContext = { + accessible_navigation: false, + bold_text: false, + disable_animations: true, + high_contrast: false, + invert_colors: false, + reduce_motion: false, + // Extra data is still valid and preserved + extra_data: 'something', + unknown_key: 123, +}; + +const MOCK_REDACTION = { + reduce_motion: { + '': { + rem: [['organization:0', 's', 0, 0]], + len: 5, + }, + }, +}; + +describe('AccessibilityContext', () => { + it('returns values according to the parameters', () => { + expect(getAccessibilityContextData({data: MOCK_ACCESSIBILITY_CONTEXT})).toEqual([ + { + key: 'accessible_navigation', + subject: 'Accessible Navigation', + value: false, + }, + {key: 'bold_text', subject: 'Bold Text', value: false}, + {key: 'disable_animations', subject: 'Disable Animations', value: true}, + {key: 'high_contrast', subject: 'High Contrast', value: false}, + {key: 'invert_colors', subject: 'Invert Colors', value: false}, + {key: 'reduce_motion', subject: 'Reduce Motion', value: false}, + { + key: 'extra_data', + subject: 'extra_data', + value: 'something', + meta: undefined, + }, + { + key: 'unknown_key', + subject: 'unknown_key', + value: 123, + meta: undefined, + }, + ]); + }); + + it('renders with meta annotations correctly', () => { + const event = EventFixture({ + _meta: {contexts: {accessibility: MOCK_REDACTION}}, + }); + + render( + + ); + + expect(screen.getByText('Accessibility')).toBeInTheDocument(); + expect(screen.getByText('Disable Animations')).toBeInTheDocument(); + expect(screen.getByText('Reduce Motion')).toBeInTheDocument(); + expect(screen.getByText(/redacted/)).toBeInTheDocument(); + }); +}); diff --git a/static/app/components/events/contexts/knownContext/accessibility.tsx b/static/app/components/events/contexts/knownContext/accessibility.tsx new file mode 100644 index 000000000000..f3c8819e6671 --- /dev/null +++ b/static/app/components/events/contexts/knownContext/accessibility.tsx @@ -0,0 +1,78 @@ +import {getContextKeys} from 'sentry/components/events/contexts/utils'; +import {t} from 'sentry/locale'; +import type {KeyValueListData} from 'sentry/types/group'; + +enum AccessibilityContextKeys { + ACCESSIBLE_NAVIGATION = 'accessible_navigation', + BOLD_TEXT = 'bold_text', + DISABLE_ANIMATIONS = 'disable_animations', + HIGH_CONTRAST = 'high_contrast', + INVERT_COLORS = 'invert_colors', + REDUCE_MOTION = 'reduce_motion', +} + +export interface AccessibilityContext { + [key: string]: any; + [AccessibilityContextKeys.ACCESSIBLE_NAVIGATION]?: boolean; + [AccessibilityContextKeys.BOLD_TEXT]?: boolean; + [AccessibilityContextKeys.DISABLE_ANIMATIONS]?: boolean; + [AccessibilityContextKeys.HIGH_CONTRAST]?: boolean; + [AccessibilityContextKeys.INVERT_COLORS]?: boolean; + [AccessibilityContextKeys.REDUCE_MOTION]?: boolean; +} + +export function getAccessibilityContextData({ + data, + meta, +}: { + data: AccessibilityContext; + meta?: Record; +}): KeyValueListData { + return getContextKeys({data}).map(ctxKey => { + switch (ctxKey) { + case AccessibilityContextKeys.ACCESSIBLE_NAVIGATION: + return { + key: ctxKey, + subject: t('Accessible Navigation'), + value: data.accessible_navigation, + }; + case AccessibilityContextKeys.BOLD_TEXT: + return { + key: ctxKey, + subject: t('Bold Text'), + value: data.bold_text, + }; + case AccessibilityContextKeys.DISABLE_ANIMATIONS: + return { + key: ctxKey, + subject: t('Disable Animations'), + value: data.disable_animations, + }; + case AccessibilityContextKeys.HIGH_CONTRAST: + return { + key: ctxKey, + subject: t('High Contrast'), + value: data.high_contrast, + }; + case AccessibilityContextKeys.INVERT_COLORS: + return { + key: ctxKey, + subject: t('Invert Colors'), + value: data.invert_colors, + }; + case AccessibilityContextKeys.REDUCE_MOTION: + return { + key: ctxKey, + subject: t('Reduce Motion'), + value: data.reduce_motion, + }; + default: + return { + key: ctxKey, + subject: ctxKey, + value: data[ctxKey], + meta: meta?.[ctxKey]?.[''], + }; + } + }); +} diff --git a/static/app/components/events/contexts/knownContext/app.spec.tsx b/static/app/components/events/contexts/knownContext/app.spec.tsx index 8860ba7849da..3b4aa44b4e3e 100644 --- a/static/app/components/events/contexts/knownContext/app.spec.tsx +++ b/static/app/components/events/contexts/knownContext/app.spec.tsx @@ -21,6 +21,12 @@ const MOCK_APP_CONTEXT: AppContext = { is_active: false, app_memory: 1048576 * 12, view_names: ['app.view1', 'app.view2'], + is_split_apks: false, + permissions: { + ACCESS_NETWORK_STATE: 'granted', + CAMERA: 'not_granted', + INTERNET: 'granted', + }, // Extra data is still valid and preserved extra_data: 'something', unknown_key: 123, @@ -73,6 +79,16 @@ describe('AppContext', () => { subject: 'View Names', value: ['app.view1', 'app.view2'], }, + {key: 'is_split_apks', subject: 'Split APKs', value: false}, + { + key: 'permissions', + subject: 'Permissions', + value: { + ACCESS_NETWORK_STATE: 'granted', + CAMERA: 'not_granted', + INTERNET: 'granted', + }, + }, { key: 'extra_data', subject: 'extra_data', diff --git a/static/app/components/events/contexts/knownContext/app.tsx b/static/app/components/events/contexts/knownContext/app.tsx index 4f851e599c24..73bdb5a23fcf 100644 --- a/static/app/components/events/contexts/knownContext/app.tsx +++ b/static/app/components/events/contexts/knownContext/app.tsx @@ -24,6 +24,8 @@ enum AppContextKeys { // XXX: From https://github.com/getsentry/sentry/issues/87238, not in the schema yet. FREE_MEMORY = 'free_memory', ARCHITECTURE = 'app_arch', + IS_SPLIT_APKS = 'is_split_apks', + PERMISSIONS = 'permissions', } export interface AppContext { @@ -43,6 +45,8 @@ export interface AppContext { [AppContextKeys.VIEW_NAMES]?: string[]; [AppContextKeys.FREE_MEMORY]?: number; [AppContextKeys.ARCHITECTURE]?: string; + [AppContextKeys.IS_SPLIT_APKS]?: boolean; + [AppContextKeys.PERMISSIONS]?: Record; } // https://github.com/getsentry/relay/blob/24.10.0/relay-event-schema/src/protocol/contexts/app.rs#L37 @@ -151,6 +155,18 @@ export function getAppContextData({ subject: t('Architecture'), value: data.app_arch, }; + case AppContextKeys.IS_SPLIT_APKS: + return { + key: ctxKey, + subject: t('Split APKs'), + value: data.is_split_apks, + }; + case AppContextKeys.PERMISSIONS: + return { + key: ctxKey, + subject: t('Permissions'), + value: data.permissions, + }; default: return { key: ctxKey, diff --git a/static/app/components/events/contexts/knownContext/dartContext.spec.tsx b/static/app/components/events/contexts/knownContext/dartContext.spec.tsx new file mode 100644 index 000000000000..e142d04fe042 --- /dev/null +++ b/static/app/components/events/contexts/knownContext/dartContext.spec.tsx @@ -0,0 +1,76 @@ +import {EventFixture} from 'sentry-fixture/event'; + +import {render, screen} from 'sentry-test/reactTestingLibrary'; + +import {ContextCard} from 'sentry/components/events/contexts/contextCard'; +import { + getDartContextData, + type DartContext, +} from 'sentry/components/events/contexts/knownContext/dartContext'; + +const MOCK_DART_CONTEXT: DartContext = { + compile_mode: 'debug', + executable: 'flutter', + resolved_executable: '/system/bin/app_process64', + script: 'file:///main.dart', + // Extra data is still valid and preserved + extra_data: 'something', + unknown_key: 123, +}; + +const MOCK_REDACTION = { + script: { + '': { + rem: [['organization:0', 's', 0, 0]], + len: 20, + }, + }, +}; + +describe('DartContext', () => { + it('returns values according to the parameters', () => { + expect(getDartContextData({data: MOCK_DART_CONTEXT})).toEqual([ + {key: 'compile_mode', subject: 'Compile Mode', value: 'debug'}, + {key: 'executable', subject: 'Executable', value: 'flutter'}, + { + key: 'resolved_executable', + subject: 'Resolved Executable', + value: '/system/bin/app_process64', + }, + {key: 'script', subject: 'Script', value: 'file:///main.dart'}, + { + key: 'extra_data', + subject: 'extra_data', + value: 'something', + meta: undefined, + }, + { + key: 'unknown_key', + subject: 'unknown_key', + value: 123, + meta: undefined, + }, + ]); + }); + + it('renders with meta annotations correctly', () => { + const event = EventFixture({ + _meta: {contexts: {dart_context: MOCK_REDACTION}}, + }); + + render( + + ); + + expect(screen.getByText('Dart')).toBeInTheDocument(); + expect(screen.getByText('Compile Mode')).toBeInTheDocument(); + expect(screen.getByText('debug')).toBeInTheDocument(); + expect(screen.getByText('Script')).toBeInTheDocument(); + expect(screen.getByText(/redacted/)).toBeInTheDocument(); + }); +}); diff --git a/static/app/components/events/contexts/knownContext/dartContext.tsx b/static/app/components/events/contexts/knownContext/dartContext.tsx new file mode 100644 index 000000000000..fc80c0f4220a --- /dev/null +++ b/static/app/components/events/contexts/knownContext/dartContext.tsx @@ -0,0 +1,62 @@ +import {getContextKeys} from 'sentry/components/events/contexts/utils'; +import {t} from 'sentry/locale'; +import type {KeyValueListData} from 'sentry/types/group'; + +enum DartContextKeys { + COMPILE_MODE = 'compile_mode', + EXECUTABLE = 'executable', + RESOLVED_EXECUTABLE = 'resolved_executable', + SCRIPT = 'script', +} + +export interface DartContext { + [key: string]: any; + [DartContextKeys.COMPILE_MODE]?: string; + [DartContextKeys.EXECUTABLE]?: string; + [DartContextKeys.RESOLVED_EXECUTABLE]?: string; + [DartContextKeys.SCRIPT]?: string; +} + +export function getDartContextData({ + data, + meta, +}: { + data: DartContext; + meta?: Record; +}): KeyValueListData { + return getContextKeys({data}).map(ctxKey => { + switch (ctxKey) { + case DartContextKeys.COMPILE_MODE: + return { + key: ctxKey, + subject: t('Compile Mode'), + value: data.compile_mode, + }; + case DartContextKeys.EXECUTABLE: + return { + key: ctxKey, + subject: t('Executable'), + value: data.executable, + }; + case DartContextKeys.RESOLVED_EXECUTABLE: + return { + key: ctxKey, + subject: t('Resolved Executable'), + value: data.resolved_executable, + }; + case DartContextKeys.SCRIPT: + return { + key: ctxKey, + subject: t('Script'), + value: data.script, + }; + default: + return { + key: ctxKey, + subject: ctxKey, + value: data[ctxKey], + meta: meta?.[ctxKey]?.[''], + }; + } + }); +} diff --git a/static/app/components/events/contexts/knownContext/device.spec.tsx b/static/app/components/events/contexts/knownContext/device.spec.tsx index fb85bb2da436..86a38d2e0029 100644 --- a/static/app/components/events/contexts/knownContext/device.spec.tsx +++ b/static/app/components/events/contexts/knownContext/device.spec.tsx @@ -35,6 +35,12 @@ const MOCK_DEVICE_CONTEXT: DeviceContext = { manufacturer: 'Google', free_storage: 508784640, model: 'Android SDK built for x86', + locale: 'en_US', + archs: ['arm64-v8a'], + chipset: 'AOSP ranchu', + connection_type: 'cellular', + low_power_mode: false, + thermal_state: 'nominal', }; const MOCK_REDACTION = { @@ -74,9 +80,8 @@ describe('DeviceContext', () => { }, { key: 'timezone', - subject: 'timezone', + subject: 'Timezone', value: 'America/Los_Angeles', - meta: undefined, }, { key: 'external_storage_size', @@ -132,6 +137,12 @@ describe('DeviceContext', () => { subject: 'Model', value: expect.anything(), }, + {key: 'locale', subject: 'Locale', value: 'en_US'}, + {key: 'archs', subject: 'Architectures', value: ['arm64-v8a']}, + {key: 'chipset', subject: 'Chipset', value: 'AOSP ranchu'}, + {key: 'connection_type', subject: 'Connection Type', value: 'cellular'}, + {key: 'low_power_mode', subject: 'Low Power Mode', value: false}, + {key: 'thermal_state', subject: 'Thermal State', value: 'nominal'}, ]); }); diff --git a/static/app/components/events/contexts/knownContext/device.tsx b/static/app/components/events/contexts/knownContext/device.tsx index cd367bd05e73..ac6dd0b9069c 100644 --- a/static/app/components/events/contexts/knownContext/device.tsx +++ b/static/app/components/events/contexts/knownContext/device.tsx @@ -421,6 +421,48 @@ export function getDeviceContextData({ subject: t('Supports Vibration'), value: data.supports_vibration, }; + case DeviceContextKey.TIMEZONE: + return { + key: ctxKey, + subject: t('Timezone'), + value: data.timezone, + }; + case DeviceContextKey.LOCALE: + return { + key: ctxKey, + subject: t('Locale'), + value: data.locale, + }; + case DeviceContextKey.ARCHS: + return { + key: ctxKey, + subject: t('Architectures'), + value: data.archs, + }; + case DeviceContextKey.CHIPSET: + return { + key: ctxKey, + subject: t('Chipset'), + value: data.chipset, + }; + case DeviceContextKey.CONNECTION_TYPE: + return { + key: ctxKey, + subject: t('Connection Type'), + value: data.connection_type, + }; + case DeviceContextKey.LOW_POWER_MODE: + return { + key: ctxKey, + subject: t('Low Power Mode'), + value: data.low_power_mode, + }; + case DeviceContextKey.THERMAL_STATE: + return { + key: ctxKey, + subject: t('Thermal State'), + value: data.thermal_state, + }; default: return { key: ctxKey, diff --git a/static/app/components/events/contexts/knownContext/flutterContext.spec.tsx b/static/app/components/events/contexts/knownContext/flutterContext.spec.tsx new file mode 100644 index 000000000000..0e159c8da474 --- /dev/null +++ b/static/app/components/events/contexts/knownContext/flutterContext.spec.tsx @@ -0,0 +1,68 @@ +import {EventFixture} from 'sentry-fixture/event'; + +import {render, screen} from 'sentry-test/reactTestingLibrary'; + +import {ContextCard} from 'sentry/components/events/contexts/contextCard'; +import { + getFlutterContextData, + type FlutterContext, +} from 'sentry/components/events/contexts/knownContext/flutterContext'; + +const MOCK_FLUTTER_CONTEXT: FlutterContext = { + default_route_name: '/', + has_render_view: 'true', + // Extra data is still valid and preserved + extra_data: 'something', + unknown_key: 123, +}; + +const MOCK_REDACTION = { + default_route_name: { + '': { + rem: [['organization:0', 's', 0, 0]], + len: 1, + }, + }, +}; + +describe('FlutterContext', () => { + it('returns values according to the parameters', () => { + expect(getFlutterContextData({data: MOCK_FLUTTER_CONTEXT})).toEqual([ + {key: 'default_route_name', subject: 'Default Route Name', value: '/'}, + {key: 'has_render_view', subject: 'Has Render View', value: 'true'}, + { + key: 'extra_data', + subject: 'extra_data', + value: 'something', + meta: undefined, + }, + { + key: 'unknown_key', + subject: 'unknown_key', + value: 123, + meta: undefined, + }, + ]); + }); + + it('renders with meta annotations correctly', () => { + const event = EventFixture({ + _meta: {contexts: {flutter_context: MOCK_REDACTION}}, + }); + + render( + + ); + + expect(screen.getByText('Flutter')).toBeInTheDocument(); + expect(screen.getByText('Has Render View')).toBeInTheDocument(); + expect(screen.getByText('true')).toBeInTheDocument(); + expect(screen.getByText('Default Route Name')).toBeInTheDocument(); + expect(screen.getByText(/redacted/)).toBeInTheDocument(); + }); +}); diff --git a/static/app/components/events/contexts/knownContext/flutterContext.tsx b/static/app/components/events/contexts/knownContext/flutterContext.tsx new file mode 100644 index 000000000000..a396e4bfb0eb --- /dev/null +++ b/static/app/components/events/contexts/knownContext/flutterContext.tsx @@ -0,0 +1,46 @@ +import {getContextKeys} from 'sentry/components/events/contexts/utils'; +import {t} from 'sentry/locale'; +import type {KeyValueListData} from 'sentry/types/group'; + +enum FlutterContextKeys { + DEFAULT_ROUTE_NAME = 'default_route_name', + HAS_RENDER_VIEW = 'has_render_view', +} + +export interface FlutterContext { + [key: string]: any; + [FlutterContextKeys.DEFAULT_ROUTE_NAME]?: string; + [FlutterContextKeys.HAS_RENDER_VIEW]?: string; +} + +export function getFlutterContextData({ + data, + meta, +}: { + data: FlutterContext; + meta?: Record; +}): KeyValueListData { + return getContextKeys({data}).map(ctxKey => { + switch (ctxKey) { + case FlutterContextKeys.DEFAULT_ROUTE_NAME: + return { + key: ctxKey, + subject: t('Default Route Name'), + value: data.default_route_name, + }; + case FlutterContextKeys.HAS_RENDER_VIEW: + return { + key: ctxKey, + subject: t('Has Render View'), + value: data.has_render_view, + }; + default: + return { + key: ctxKey, + subject: ctxKey, + value: data[ctxKey], + meta: meta?.[ctxKey]?.[''], + }; + } + }); +} diff --git a/static/app/components/events/contexts/knownContext/reactNativeContext.spec.tsx b/static/app/components/events/contexts/knownContext/reactNativeContext.spec.tsx new file mode 100644 index 000000000000..536bd10ebd26 --- /dev/null +++ b/static/app/components/events/contexts/knownContext/reactNativeContext.spec.tsx @@ -0,0 +1,86 @@ +import {EventFixture} from 'sentry-fixture/event'; + +import {render, screen} from 'sentry-test/reactTestingLibrary'; + +import {ContextCard} from 'sentry/components/events/contexts/contextCard'; +import { + getReactNativeContextData, + type ReactNativeContext, +} from 'sentry/components/events/contexts/knownContext/reactNativeContext'; + +const MOCK_REACT_NATIVE_CONTEXT: ReactNativeContext = { + expo: false, + fabric: true, + hermes_debug_info: false, + hermes_version: '250829098.0.10', + js_engine: 'hermes', + react_native_version: '0.85.1', + turbo_module: true, + // Extra data is still valid and preserved + extra_data: 'something', + unknown_key: 123, +}; + +const MOCK_REDACTION = { + hermes_version: { + '': { + rem: [['organization:0', 's', 0, 0]], + len: 15, + }, + }, +}; + +describe('ReactNativeContext', () => { + it('returns values according to the parameters', () => { + expect(getReactNativeContextData({data: MOCK_REACT_NATIVE_CONTEXT})).toEqual([ + {key: 'expo', subject: 'Expo', value: false}, + {key: 'fabric', subject: 'Fabric', value: true}, + {key: 'hermes_debug_info', subject: 'Hermes Debug Info', value: false}, + { + key: 'hermes_version', + subject: 'Hermes Version', + value: '250829098.0.10', + }, + {key: 'js_engine', subject: 'JS Engine', value: 'hermes'}, + { + key: 'react_native_version', + subject: 'React Native Version', + value: '0.85.1', + }, + {key: 'turbo_module', subject: 'Turbo Module', value: true}, + { + key: 'extra_data', + subject: 'extra_data', + value: 'something', + meta: undefined, + }, + { + key: 'unknown_key', + subject: 'unknown_key', + value: 123, + meta: undefined, + }, + ]); + }); + + it('renders with meta annotations correctly', () => { + const event = EventFixture({ + _meta: {contexts: {react_native_context: MOCK_REDACTION}}, + }); + + render( + + ); + + expect(screen.getByText('React Native')).toBeInTheDocument(); + expect(screen.getByText('JS Engine')).toBeInTheDocument(); + expect(screen.getByText('hermes')).toBeInTheDocument(); + expect(screen.getByText('Hermes Version')).toBeInTheDocument(); + expect(screen.getByText(/redacted/)).toBeInTheDocument(); + }); +}); diff --git a/static/app/components/events/contexts/knownContext/reactNativeContext.tsx b/static/app/components/events/contexts/knownContext/reactNativeContext.tsx new file mode 100644 index 000000000000..258a5d11c306 --- /dev/null +++ b/static/app/components/events/contexts/knownContext/reactNativeContext.tsx @@ -0,0 +1,86 @@ +import {getContextKeys} from 'sentry/components/events/contexts/utils'; +import {t} from 'sentry/locale'; +import type {KeyValueListData} from 'sentry/types/group'; + +enum ReactNativeContextKeys { + EXPO = 'expo', + FABRIC = 'fabric', + HERMES_DEBUG_INFO = 'hermes_debug_info', + HERMES_VERSION = 'hermes_version', + JS_ENGINE = 'js_engine', + REACT_NATIVE_VERSION = 'react_native_version', + TURBO_MODULE = 'turbo_module', +} + +export interface ReactNativeContext { + [key: string]: any; + [ReactNativeContextKeys.EXPO]?: boolean; + [ReactNativeContextKeys.FABRIC]?: boolean; + [ReactNativeContextKeys.HERMES_DEBUG_INFO]?: boolean; + [ReactNativeContextKeys.HERMES_VERSION]?: string; + [ReactNativeContextKeys.JS_ENGINE]?: string; + [ReactNativeContextKeys.REACT_NATIVE_VERSION]?: string; + [ReactNativeContextKeys.TURBO_MODULE]?: boolean; +} + +export function getReactNativeContextData({ + data, + meta, +}: { + data: ReactNativeContext; + meta?: Record; +}): KeyValueListData { + return getContextKeys({data}).map(ctxKey => { + switch (ctxKey) { + case ReactNativeContextKeys.EXPO: + return { + key: ctxKey, + subject: t('Expo'), + value: data.expo, + }; + case ReactNativeContextKeys.FABRIC: + return { + key: ctxKey, + subject: t('Fabric'), + value: data.fabric, + }; + case ReactNativeContextKeys.HERMES_DEBUG_INFO: + return { + key: ctxKey, + subject: t('Hermes Debug Info'), + value: data.hermes_debug_info, + }; + case ReactNativeContextKeys.HERMES_VERSION: + return { + key: ctxKey, + subject: t('Hermes Version'), + value: data.hermes_version, + }; + case ReactNativeContextKeys.JS_ENGINE: + return { + key: ctxKey, + subject: t('JS Engine'), + value: data.js_engine, + }; + case ReactNativeContextKeys.REACT_NATIVE_VERSION: + return { + key: ctxKey, + subject: t('React Native Version'), + value: data.react_native_version, + }; + case ReactNativeContextKeys.TURBO_MODULE: + return { + key: ctxKey, + subject: t('Turbo Module'), + value: data.turbo_module, + }; + default: + return { + key: ctxKey, + subject: ctxKey, + value: data[ctxKey], + meta: meta?.[ctxKey]?.[''], + }; + } + }); +} diff --git a/static/app/components/events/contexts/utils.tsx b/static/app/components/events/contexts/utils.tsx index d57ba74602a8..7b41bfea8a3c 100644 --- a/static/app/components/events/contexts/utils.tsx +++ b/static/app/components/events/contexts/utils.tsx @@ -12,16 +12,20 @@ import { getLogoImage, type ContextIconProps, } from 'sentry/components/events/contexts/contextIcon'; +import {getAccessibilityContextData} from 'sentry/components/events/contexts/knownContext/accessibility'; import {getAppContextData} from 'sentry/components/events/contexts/knownContext/app'; import {getBrowserContextData} from 'sentry/components/events/contexts/knownContext/browser'; import {getCloudResourceContextData} from 'sentry/components/events/contexts/knownContext/cloudResource'; import {getCultureContextData} from 'sentry/components/events/contexts/knownContext/culture'; +import {getDartContextData} from 'sentry/components/events/contexts/knownContext/dartContext'; import {getDeviceContextData} from 'sentry/components/events/contexts/knownContext/device'; +import {getFlutterContextData} from 'sentry/components/events/contexts/knownContext/flutterContext'; import {getGPUContextData} from 'sentry/components/events/contexts/knownContext/gpu'; import {getMemoryInfoContext} from 'sentry/components/events/contexts/knownContext/memoryInfo'; import {getMissingInstrumentationContextData} from 'sentry/components/events/contexts/knownContext/missingInstrumentation'; import {getOperatingSystemContextData} from 'sentry/components/events/contexts/knownContext/os'; import {getProfileContextData} from 'sentry/components/events/contexts/knownContext/profile'; +import {getReactNativeContextData} from 'sentry/components/events/contexts/knownContext/reactNativeContext'; import {getReplayContextData} from 'sentry/components/events/contexts/knownContext/replay'; import {getRuntimeContextData} from 'sentry/components/events/contexts/knownContext/runtime'; import {getStateContextData} from 'sentry/components/events/contexts/knownContext/state'; @@ -293,6 +297,12 @@ export function getContextTitle({ return t('OTA Updates'); case 'react_native_context': return t('React Native'); + case 'accessibility': + return t('Accessibility'); + case 'flutter_context': + return t('Flutter'); + case 'dart_context': + return t('Dart'); default: return contextType; } @@ -435,6 +445,14 @@ export function getFormattedContextData({ return getCultureContextData({data: contextValue, meta}); case 'missing_instrumentation': return getMissingInstrumentationContextData({data: contextValue, meta}); + case 'accessibility': + return getAccessibilityContextData({data: contextValue, meta}); + case 'react_native_context': + return getReactNativeContextData({data: contextValue, meta}); + case 'flutter_context': + return getFlutterContextData({data: contextValue, meta}); + case 'dart_context': + return getDartContextData({data: contextValue, meta}); default: return getContextKeys({data: contextValue}).map(ctxKey => ({ key: ctxKey, diff --git a/static/app/types/event.tsx b/static/app/types/event.tsx index e159a6de9b1b..ad772db2ae15 100644 --- a/static/app/types/event.tsx +++ b/static/app/types/event.tsx @@ -433,6 +433,13 @@ export enum DeviceContextKey { SUPPORTS_LOCATION_SERVICE = 'supports_location_service', SUPPORTS_VIBRATION = 'supports_vibration', USABLE_MEMORY = 'usable_memory', + TIMEZONE = 'timezone', + LOCALE = 'locale', + ARCHS = 'archs', + CHIPSET = 'chipset', + CONNECTION_TYPE = 'connection_type', + LOW_POWER_MODE = 'low_power_mode', + THERMAL_STATE = 'thermal_state', } // https://develop.sentry.dev/sdk/event-payloads/contexts/#device-context @@ -478,10 +485,16 @@ export interface DeviceContext [DeviceContextKey.SUPPORTS_LOCATION_SERVICE]?: boolean; [DeviceContextKey.SUPPORTS_VIBRATION]?: boolean; [DeviceContextKey.USABLE_MEMORY]?: number; + [DeviceContextKey.LOCALE]?: string; + [DeviceContextKey.ARCHS]?: string[]; + [DeviceContextKey.CHIPSET]?: string; + [DeviceContextKey.CONNECTION_TYPE]?: string; + [DeviceContextKey.LOW_POWER_MODE]?: boolean; + // This field is deprecated in favour of timezone field in culture context + [DeviceContextKey.TIMEZONE]?: string; + [DeviceContextKey.THERMAL_STATE]?: string; // This field is deprecated in favour of locale field in culture context language?: string; - // This field is deprecated in favour of timezone field in culture context - timezone?: string; } enum RuntimeContextKey {