react-native-inapp-inspector 1.1.27 → 1.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +29 -46
  2. package/dist/commonjs/components/AppHeaderLogo.js +12 -15
  3. package/dist/commonjs/components/ConsoleLogCard.js +31 -7
  4. package/dist/commonjs/components/CopyButton.js +15 -1
  5. package/dist/commonjs/components/DomainHeader.js +56 -28
  6. package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
  7. package/dist/commonjs/components/ErrorBoundary.js +530 -100
  8. package/dist/commonjs/components/HighlightText.js +7 -1
  9. package/dist/commonjs/components/Inspector/AnalyticsTab.js +190 -126
  10. package/dist/commonjs/components/Inspector/BundleTab.d.ts +1 -0
  11. package/dist/commonjs/components/Inspector/BundleTab.js +145 -21
  12. package/dist/commonjs/components/Inspector/CrashTab.js +0 -8
  13. package/dist/commonjs/components/Inspector/InspectorHeader.js +17 -3
  14. package/dist/commonjs/components/Inspector/LogDetail.js +8 -5
  15. package/dist/commonjs/components/Inspector/MainScreen.js +4 -0
  16. package/dist/commonjs/components/Inspector/NetworkDetail.js +65 -24
  17. package/dist/commonjs/components/Inspector/PerformanceTab.d.ts +5 -0
  18. package/dist/commonjs/components/Inspector/PerformanceTab.js +588 -155
  19. package/dist/commonjs/components/Inspector/SettingsPanel.js +57 -22
  20. package/dist/commonjs/components/Inspector/TabBar.js +13 -1
  21. package/dist/commonjs/components/JsonViewer.js +25 -3
  22. package/dist/commonjs/components/LogCard.js +173 -40
  23. package/dist/commonjs/components/NetworkIcons.d.ts +112 -102
  24. package/dist/commonjs/components/Toast.d.ts +3 -0
  25. package/dist/commonjs/components/Toast.js +152 -0
  26. package/dist/commonjs/components/TouchableScale.d.ts +1 -0
  27. package/dist/commonjs/components/TouchableScale.js +3 -3
  28. package/dist/commonjs/components/TreeNode.js +1 -1
  29. package/dist/commonjs/constants/index.js +6 -6
  30. package/dist/commonjs/constants/version.d.ts +1 -1
  31. package/dist/commonjs/constants/version.js +1 -1
  32. package/dist/commonjs/customHooks/analyticsLogger.d.ts +1 -11
  33. package/dist/commonjs/customHooks/analyticsLogger.js +8 -1
  34. package/dist/commonjs/customHooks/bundleAnalyzer.js +121 -124
  35. package/dist/commonjs/customHooks/networkLogger.d.ts +1 -0
  36. package/dist/commonjs/customHooks/networkLogger.js +16 -0
  37. package/dist/commonjs/customHooks/performanceTracker.d.ts +74 -0
  38. package/dist/commonjs/customHooks/performanceTracker.js +546 -392
  39. package/dist/commonjs/customHooks/reduxLogger.d.ts +1 -0
  40. package/dist/commonjs/customHooks/reduxLogger.js +3 -1
  41. package/dist/commonjs/helpers/index.d.ts +4 -0
  42. package/dist/commonjs/helpers/index.js +92 -69
  43. package/dist/commonjs/helpers/toast.d.ts +4 -0
  44. package/dist/commonjs/helpers/toast.js +20 -0
  45. package/dist/commonjs/i18n/locales/en.json +229 -5
  46. package/dist/commonjs/index.d.ts +1 -1
  47. package/dist/commonjs/index.js +36 -2
  48. package/dist/commonjs/styles/index.d.ts +63 -15
  49. package/dist/commonjs/styles/index.js +79 -32
  50. package/dist/commonjs/types/interfaces.d.ts +3 -0
  51. package/dist/esm/components/AppHeaderLogo.js +12 -15
  52. package/dist/esm/components/ConsoleLogCard.js +33 -9
  53. package/dist/esm/components/CopyButton.js +15 -1
  54. package/dist/esm/components/DomainHeader.js +56 -28
  55. package/dist/esm/components/ErrorBoundary.d.ts +1 -1
  56. package/dist/esm/components/ErrorBoundary.js +498 -101
  57. package/dist/esm/components/HighlightText.js +7 -1
  58. package/dist/esm/components/Inspector/AnalyticsTab.js +191 -127
  59. package/dist/esm/components/Inspector/BundleTab.d.ts +1 -0
  60. package/dist/esm/components/Inspector/BundleTab.js +145 -23
  61. package/dist/esm/components/Inspector/CrashTab.js +0 -8
  62. package/dist/esm/components/Inspector/InspectorHeader.js +18 -4
  63. package/dist/esm/components/Inspector/LogDetail.js +10 -7
  64. package/dist/esm/components/Inspector/MainScreen.js +4 -0
  65. package/dist/esm/components/Inspector/NetworkDetail.js +66 -25
  66. package/dist/esm/components/Inspector/PerformanceTab.d.ts +5 -0
  67. package/dist/esm/components/Inspector/PerformanceTab.js +591 -158
  68. package/dist/esm/components/Inspector/SettingsPanel.js +57 -22
  69. package/dist/esm/components/Inspector/TabBar.js +13 -1
  70. package/dist/esm/components/JsonViewer.js +25 -3
  71. package/dist/esm/components/LogCard.js +175 -42
  72. package/dist/esm/components/NetworkIcons.d.ts +112 -102
  73. package/dist/esm/components/Toast.d.ts +3 -0
  74. package/dist/esm/components/Toast.js +117 -0
  75. package/dist/esm/components/TouchableScale.d.ts +1 -0
  76. package/dist/esm/components/TouchableScale.js +3 -3
  77. package/dist/esm/components/TreeNode.js +1 -1
  78. package/dist/esm/constants/index.js +6 -6
  79. package/dist/esm/constants/version.d.ts +1 -1
  80. package/dist/esm/constants/version.js +1 -1
  81. package/dist/esm/customHooks/analyticsLogger.d.ts +1 -11
  82. package/dist/esm/customHooks/analyticsLogger.js +6 -0
  83. package/dist/esm/customHooks/bundleAnalyzer.js +121 -124
  84. package/dist/esm/customHooks/networkLogger.d.ts +1 -0
  85. package/dist/esm/customHooks/networkLogger.js +16 -0
  86. package/dist/esm/customHooks/performanceTracker.d.ts +74 -0
  87. package/dist/esm/customHooks/performanceTracker.js +531 -391
  88. package/dist/esm/customHooks/reduxLogger.d.ts +1 -0
  89. package/dist/esm/customHooks/reduxLogger.js +1 -0
  90. package/dist/esm/helpers/index.d.ts +4 -0
  91. package/dist/esm/helpers/index.js +87 -69
  92. package/dist/esm/helpers/toast.d.ts +4 -0
  93. package/dist/esm/helpers/toast.js +15 -0
  94. package/dist/esm/i18n/locales/en.json +229 -5
  95. package/dist/esm/index.d.ts +1 -1
  96. package/dist/esm/index.js +24 -3
  97. package/dist/esm/styles/index.d.ts +63 -15
  98. package/dist/esm/styles/index.js +79 -32
  99. package/dist/esm/types/interfaces.d.ts +3 -0
  100. package/package.json +4 -1
@@ -8,6 +8,12 @@ const react_native_1 = require("react-native");
8
8
  // Helpers
9
9
  const helpers_1 = require("../helpers");
10
10
  const HighlightText = react_1.default.memo(function HighlightText({ text, search, style, highlightStyle, detectLinks, numberOfLines, ...rest }) {
11
+ // Optimization: For huge strings (> 20KB) with no active search, bypass all splitting/regex overhead
12
+ if (!text || (text.length > 20000 && !search && !detectLinks)) {
13
+ return (<react_native_1.Text style={style} numberOfLines={numberOfLines} {...rest}>
14
+ {text}
15
+ </react_native_1.Text>);
16
+ }
11
17
  // Regex to detect absolute URLs
12
18
  const URL_REGEX = /(https?:\/\/[^\s]+)/g;
13
19
  const renderNormalOrHighlighted = (subText, keyPrefix) => {
@@ -22,7 +28,7 @@ const HighlightText = react_1.default.memo(function HighlightText({ text, search
22
28
  </react_native_1.Text>) : (<react_native_1.Text key={i}>{part}</react_native_1.Text>))}
23
29
  </react_native_1.Text>);
24
30
  };
25
- if (detectLinks && text) {
31
+ if (detectLinks && text && text.length < 20000) {
26
32
  const parts = text.split(URL_REGEX);
27
33
  return (<react_native_1.Text style={style} numberOfLines={numberOfLines} {...rest}>
28
34
  {parts.map((part, i) => {
@@ -46,11 +46,14 @@ const EndOfListFooter_1 = __importDefault(require("../EndOfListFooter"));
46
46
  const styles_1 = __importDefault(require("../../styles"));
47
47
  const AppColors_1 = require("../../styles/AppColors");
48
48
  const AppFonts_1 = require("../../styles/AppFonts");
49
+ const i18n_1 = require("../../i18n");
50
+ const react_native_svg_1 = __importStar(require("react-native-svg"));
49
51
  const TouchableScale_1 = __importDefault(require("../TouchableScale"));
50
52
  const analyticsLogger_1 = require("../../customHooks/analyticsLogger");
51
53
  const helpers_1 = require("../../helpers");
52
54
  const NetworkIcons_1 = require("../NetworkIcons");
53
55
  const AnalyticsHeader = react_1.default.memo(() => {
56
+ const { t } = (0, i18n_1.useTranslation)();
54
57
  const { analyticsEvents, filteredAnalyticsEvents, analyticsFilters, setAnalyticsFilters, analyticsHeaderExpanded, setAnalyticsHeaderExpanded, } = (0, InspectorContext_1.useInspector)();
55
58
  const userId = (0, analyticsLogger_1.getCurrentUserId)();
56
59
  const userProperties = (0, analyticsLogger_1.getCurrentUserProperties)();
@@ -135,20 +138,31 @@ const AnalyticsHeader = react_1.default.memo(() => {
135
138
  }
136
139
  });
137
140
  };
138
- // 12-Bucket GA4 Realtime Stacked Histogram Graph (-30m / 30s to NOW)
141
+ // 12-Bucket GA4 Realtime Stacked Histogram & Spline Wave Graph (-30m / 30s to NOW)
139
142
  const BUCKET_COUNT = 12;
140
- const chartHeight = 56;
141
- const histogramBars = (0, react_1.useMemo)(() => {
142
- const buckets = Array.from({ length: BUCKET_COUNT }, () => ({
143
- ecommerce: 0,
144
- page_view: 0,
145
- system: 0,
146
- custom: 0,
147
- total: 0,
148
- }));
143
+ const chartHeight = 64;
144
+ const svgWidth = 320;
145
+ const [selectedBucketIdx, setSelectedBucketIdx] = (0, react_1.useState)(null);
146
+ const histogramData = (0, react_1.useMemo)(() => {
147
+ const buckets = [];
149
148
  const now = Date.now();
150
149
  const windowMs = 60000; // 60s window
151
150
  const bucketDuration = windowMs / BUCKET_COUNT;
151
+ for (let i = 0; i < BUCKET_COUNT; i++) {
152
+ const bucketAgeSec = Math.round(((BUCKET_COUNT - 1 - i) * bucketDuration) / 1000);
153
+ buckets.push({
154
+ index: i,
155
+ ecommerce: 0,
156
+ page_view: 0,
157
+ system: 0,
158
+ custom: 0,
159
+ total: 0,
160
+ x: (i / (BUCKET_COUNT - 1)) * (svgWidth - 24) + 12,
161
+ y: chartHeight - 12,
162
+ isLatest: i === BUCKET_COUNT - 1,
163
+ ageLabel: i === BUCKET_COUNT - 1 ? t('analytics.timeNow') : `-${bucketAgeSec}s`,
164
+ });
165
+ }
152
166
  for (const e of filteredAnalyticsEvents) {
153
167
  const age = now - e.timestamp;
154
168
  if (age >= 0 && age < windowMs) {
@@ -169,30 +183,43 @@ const AnalyticsHeader = react_1.default.memo(() => {
169
183
  }
170
184
  }
171
185
  const maxVal = Math.max(...buckets.map(b => b.total), 4);
172
- return buckets.map((b, idx) => {
173
- const totalH = Math.max((b.total / maxVal) * (chartHeight - 14), b.total > 0 ? 8 : 2.5);
174
- const ecomH = b.total > 0 ? (b.ecommerce / b.total) * totalH : 0;
175
- const screenH = b.total > 0 ? (b.page_view / b.total) * totalH : 0;
176
- const sysH = b.total > 0 ? (b.system / b.total) * totalH : 0;
177
- const custH = b.total > 0 ? (b.custom / b.total) * totalH : totalH;
178
- return {
179
- index: idx,
180
- total: b.total,
181
- totalHeight: totalH,
182
- ecomHeight: ecomH,
183
- screenHeight: screenH,
184
- sysHeight: sysH,
185
- custHeight: custH,
186
- isLatest: idx === BUCKET_COUNT - 1,
187
- };
186
+ buckets.forEach(b => {
187
+ const normalizedH = (b.total / maxVal) * (chartHeight - 22);
188
+ b.y = chartHeight - 10 - normalizedH;
188
189
  });
189
- }, [filteredAnalyticsEvents, chartHeight]);
190
+ // Generate Cubic Bézier Spline paths
191
+ let linePath = `M ${buckets[0].x.toFixed(1)} ${buckets[0].y.toFixed(1)}`;
192
+ for (let i = 0; i < buckets.length - 1; i++) {
193
+ const p0 = buckets[Math.max(0, i - 1)];
194
+ const p1 = buckets[i];
195
+ const p2 = buckets[i + 1];
196
+ const p3 = buckets[Math.min(buckets.length - 1, i + 2)];
197
+ const cp1x = p1.x + (p2.x - p0.x) / 6;
198
+ const cp1y = p1.y + (p2.y - p0.y) / 6;
199
+ const cp2x = p2.x - (p3.x - p1.x) / 6;
200
+ const cp2y = p2.y - (p3.y - p1.y) / 6;
201
+ linePath += ` C ${cp1x.toFixed(1)} ${cp1y.toFixed(1)}, ${cp2x.toFixed(1)} ${cp2y.toFixed(1)}, ${p2.x.toFixed(1)} ${p2.y.toFixed(1)}`;
202
+ }
203
+ const lastB = buckets[buckets.length - 1];
204
+ const firstB = buckets[0];
205
+ const areaPath = `${linePath} L ${lastB.x.toFixed(1)} ${chartHeight - 4} L ${firstB.x.toFixed(1)} ${chartHeight - 4} Z`;
206
+ const peakVal = Math.max(...buckets.map(b => b.total), 0);
207
+ const eventRate = Math.round(buckets.reduce((a, b) => a + b.total, 0));
208
+ return {
209
+ buckets,
210
+ linePath,
211
+ areaPath,
212
+ peakVal,
213
+ eventRate,
214
+ };
215
+ }, [filteredAnalyticsEvents, chartHeight, svgWidth, t]);
216
+ const selectedBucket = selectedBucketIdx != null ? histogramData.buckets[selectedBucketIdx] : null;
190
217
  return (<react_native_1.View style={styles_1.default.analyticsHeaderCard}>
191
218
  {/* ── Top Header Row (GA4 Style) ─────────────────────────────────────── */}
192
219
  <react_native_1.View style={styles_1.default.analyticsHeaderTop}>
193
220
  <react_native_1.View style={{ flex: 1 }}>
194
221
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
195
- <react_native_1.Text style={styles_1.default.analyticsHeaderTitle}>Users in last 30 minutes</react_native_1.Text>
222
+ <react_native_1.Text style={styles_1.default.analyticsHeaderTitle}>{t('analytics.realtimeStream')}</react_native_1.Text>
196
223
  <react_native_1.View style={[
197
224
  styles_1.default.statusDot,
198
225
  {
@@ -210,11 +237,11 @@ const AnalyticsHeader = react_1.default.memo(() => {
210
237
  fontFamily: AppFonts_1.AppFonts.interBold,
211
238
  },
212
239
  ]}>
213
- {isTrackingEnabled ? 'Realtime' : 'Paused'}
240
+ {isTrackingEnabled ? t('performance.live') : t('common.pause')}
214
241
  </react_native_1.Text>
215
242
  </react_native_1.View>
216
243
  <react_native_1.Text style={styles_1.default.analyticsHeaderSubtitle} numberOfLines={1}>
217
- {userId ? `User: ${userId}` : 'Anonymous Session'}
244
+ {userId ? `${t('analytics.userId')}: ${userId}` : t('analytics.emptySubtitle')}
218
245
  </react_native_1.Text>
219
246
  </react_native_1.View>
220
247
 
@@ -223,7 +250,7 @@ const AnalyticsHeader = react_1.default.memo(() => {
223
250
  setAnalyticsHeaderExpanded(!analyticsHeaderExpanded);
224
251
  }}>
225
252
  <react_native_1.Text style={styles_1.default.analyticsHeaderToggleText}>
226
- {analyticsHeaderExpanded ? 'Hide Info' : 'Session Info'}
253
+ {analyticsHeaderExpanded ? t('common.close') : t('analytics.eventDetails')}
227
254
  </react_native_1.Text>
228
255
  </react_native_1.TouchableOpacity>
229
256
  </react_native_1.View>
@@ -243,7 +270,7 @@ const AnalyticsHeader = react_1.default.memo(() => {
243
270
  flexDirection: 'row',
244
271
  justifyContent: 'space-between',
245
272
  alignItems: 'flex-start',
246
- marginBottom: 8,
273
+ marginBottom: 6,
247
274
  }}>
248
275
  <react_native_1.View>
249
276
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'baseline', gap: 6 }}>
@@ -260,13 +287,33 @@ const AnalyticsHeader = react_1.default.memo(() => {
260
287
  fontSize: 10.5,
261
288
  color: AppColors_1.AppColors.grayTextWeak,
262
289
  }}>
263
- events in window
290
+ {t('analytics.eventsInWindow')}
264
291
  </react_native_1.Text>
265
292
  </react_native_1.View>
266
293
  </react_native_1.View>
267
294
 
268
- {/* Realtime Badges */}
295
+ {/* Realtime Rate Badges */}
269
296
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
297
+ <react_native_1.View style={{
298
+ flexDirection: 'row',
299
+ alignItems: 'center',
300
+ gap: 3,
301
+ backgroundColor: `${AppColors_1.AppColors.purple}14`,
302
+ paddingHorizontal: 6,
303
+ paddingVertical: 2.5,
304
+ borderRadius: 4,
305
+ borderWidth: 1,
306
+ borderColor: `${AppColors_1.AppColors.purple}2E`,
307
+ }}>
308
+ <react_native_1.Text style={{
309
+ fontFamily: AppFonts_1.AppFonts.interBold,
310
+ fontSize: 9.5,
311
+ color: AppColors_1.AppColors.purple,
312
+ }}>
313
+ {t('analytics.eventVelocity', { rate: histogramData.eventRate })}
314
+ </react_native_1.Text>
315
+ </react_native_1.View>
316
+
270
317
  {categoryStats.totalRevenue > 0 && (<react_native_1.View style={{
271
318
  flexDirection: 'row',
272
319
  alignItems: 'center',
@@ -287,127 +334,143 @@ const AnalyticsHeader = react_1.default.memo(() => {
287
334
  ${categoryStats.totalRevenue.toFixed(2)}
288
335
  </react_native_1.Text>
289
336
  </react_native_1.View>)}
290
- <react_native_1.View style={{
291
- flexDirection: 'row',
292
- alignItems: 'center',
293
- gap: 4,
294
- backgroundColor: `${AppColors_1.AppColors.brandPurple}14`,
295
- paddingHorizontal: 6,
296
- paddingVertical: 2.5,
297
- borderRadius: 4,
298
- borderWidth: 1,
299
- borderColor: `${AppColors_1.AppColors.brandPurple}2E`,
300
- }}>
301
- <NetworkIcons_1.TargetGoalIcon color={AppColors_1.AppColors.brandPurple} size={10}/>
302
- <react_native_1.Text style={{
303
- fontFamily: AppFonts_1.AppFonts.interBold,
304
- fontSize: 9.5,
305
- color: AppColors_1.AppColors.brandPurple,
306
- }}>
307
- Live Telemetry
308
- </react_native_1.Text>
309
- </react_native_1.View>
310
337
  </react_native_1.View>
311
338
  </react_native_1.View>
312
339
 
313
- {/* GA4 Stacked Realtime Histogram Bar Graph */}
314
- <react_native_1.View style={{
315
- height: chartHeight,
340
+ {/* ── Crashlytics-Style Multi-Bar Histogram with Trendline Overlay ── */}
341
+ <react_native_1.View style={{ height: chartHeight, position: 'relative' }}>
342
+ <react_native_svg_1.default width="100%" height={chartHeight} viewBox={`0 0 ${svgWidth} ${chartHeight}`}>
343
+ <react_native_svg_1.Defs>
344
+ <react_native_svg_1.LinearGradient id="crashlyticsBarGrad" x1="0" y1="0" x2="0" y2="1">
345
+ <react_native_svg_1.Stop offset="0%" stopColor="#8B5CF6" stopOpacity="0.9"/>
346
+ <react_native_svg_1.Stop offset="100%" stopColor="#6366F1" stopOpacity="0.6"/>
347
+ </react_native_svg_1.LinearGradient>
348
+ <react_native_svg_1.LinearGradient id="crashlyticsAreaGrad" x1="0" y1="0" x2="0" y2="1">
349
+ <react_native_svg_1.Stop offset="0%" stopColor="#8B5CF6" stopOpacity="0.25"/>
350
+ <react_native_svg_1.Stop offset="80%" stopColor="#8B5CF6" stopOpacity="0.04"/>
351
+ <react_native_svg_1.Stop offset="100%" stopColor="#8B5CF6" stopOpacity="0.0"/>
352
+ </react_native_svg_1.LinearGradient>
353
+ </react_native_svg_1.Defs>
354
+
355
+ {/* Subtle Grid Guidelines */}
356
+ <react_native_svg_1.Line x1="6" y1={chartHeight - 6} x2={svgWidth - 6} y2={chartHeight - 6} stroke="#E2E8F0" strokeWidth="1"/>
357
+ <react_native_svg_1.Line x1="6" y1={chartHeight / 2} x2={svgWidth - 6} y2={chartHeight / 2} stroke="#F1F5F9" strokeWidth="1" strokeDasharray="4,4"/>
358
+
359
+ {/* Glowing Area Underlay */}
360
+ <react_native_svg_1.Path d={histogramData.areaPath} fill="url(#crashlyticsAreaGrad)"/>
361
+
362
+ {/* Vertical Crashlytics Histogram Bars */}
363
+ {histogramData.buckets.map((b, idx) => {
364
+ const isSelected = selectedBucketIdx === idx;
365
+ const barWidth = 10;
366
+ const barX = b.x - barWidth / 2;
367
+ const barHeight = Math.max(3, chartHeight - 8 - b.y);
368
+ const barY = chartHeight - 8 - barHeight;
369
+ return (<react_native_svg_1.G key={`bar-${b.index}`}>
370
+ {/* Background slot */}
371
+ <react_native_svg_1.Rect x={barX} y={6} width={barWidth} height={chartHeight - 14} rx={3} fill={isSelected ? '#EDE9FE' : '#F8FAFC'}/>
372
+
373
+ {/* Active Event Bar */}
374
+ {b.total > 0 && (<react_native_svg_1.Rect x={barX} y={barY} width={barWidth} height={barHeight} rx={3} fill="url(#crashlyticsBarGrad)"/>)}
375
+
376
+ {/* Selected Cursor Line */}
377
+ {isSelected && (<react_native_svg_1.Line x1={b.x} y1={4} x2={b.x} y2={chartHeight - 6} stroke="#8B5CF6" strokeWidth="1.5" strokeDasharray="2,2"/>)}
378
+ </react_native_svg_1.G>);
379
+ })}
380
+
381
+ {/* Crashlytics Apex Trendline */}
382
+ <react_native_svg_1.Path d={histogramData.linePath} fill="none" stroke="#8B5CF6" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
383
+
384
+ {/* Pulsing Dot on Current Active Time Bucket */}
385
+ {histogramData.buckets.length > 0 && (<react_native_svg_1.G>
386
+ <react_native_svg_1.Circle cx={histogramData.buckets[histogramData.buckets.length - 1].x} cy={histogramData.buckets[histogramData.buckets.length - 1].y} r="5.5" fill="#8B5CF6" opacity="0.25"/>
387
+ <react_native_svg_1.Circle cx={histogramData.buckets[histogramData.buckets.length - 1].x} cy={histogramData.buckets[histogramData.buckets.length - 1].y} r="3" fill="#7C3AED"/>
388
+ </react_native_svg_1.G>)}
389
+ </react_native_svg_1.default>
390
+
391
+ {/* Invisible Touch Columns for Interactive Bucket Selection */}
392
+ <react_native_1.View style={{
393
+ position: 'absolute',
394
+ top: 0,
395
+ left: 0,
396
+ right: 0,
397
+ bottom: 0,
316
398
  flexDirection: 'row',
317
- alignItems: 'flex-end',
318
- justifyContent: 'space-between',
319
- paddingHorizontal: 2,
320
- paddingBottom: 2,
321
- borderBottomWidth: 1,
322
- borderBottomColor: AppColors_1.AppColors.dividerColor,
323
399
  }}>
324
- {histogramBars.map(bar => (<react_native_1.View key={bar.index} style={{
325
- flex: 1,
400
+ {histogramData.buckets.map((b, idx) => (<react_native_1.TouchableOpacity key={b.index} style={{ flex: 1, height: '100%' }} activeOpacity={0.8} onPress={() => setSelectedBucketIdx(selectedBucketIdx === idx ? null : idx)}/>))}
401
+ </react_native_1.View>
402
+ </react_native_1.View>
403
+
404
+ {/* Selected Bucket Quick Breakdown Overlay */}
405
+ {selectedBucket && (<react_native_1.View style={{
406
+ flexDirection: 'row',
326
407
  alignItems: 'center',
327
- justifyContent: 'flex-end',
328
- height: '100%',
329
- marginHorizontal: 1.5,
408
+ justifyContent: 'space-between',
409
+ backgroundColor: AppColors_1.AppColors.white,
410
+ borderRadius: 6,
411
+ paddingHorizontal: 8,
412
+ paddingVertical: 4,
413
+ marginTop: 4,
414
+ borderWidth: 1,
415
+ borderColor: AppColors_1.AppColors.brandPurple,
330
416
  }}>
331
- {bar.total > 0 && (<react_native_1.Text style={{
332
- fontFamily: AppFonts_1.AppFonts.interBold,
333
- fontSize: 7.5,
334
- color: bar.isLatest
335
- ? AppColors_1.AppColors.brandPurple
336
- : AppColors_1.AppColors.grayTextWeak,
337
- marginBottom: 2,
338
- }}>
339
- {bar.total}
340
- </react_native_1.Text>)}
341
- {/* Stacked Category Segments Column */}
342
- <react_native_1.View style={{
343
- width: '100%',
344
- maxWidth: 15,
345
- height: bar.totalHeight,
346
- borderRadius: 3,
347
- overflow: 'hidden',
348
- backgroundColor: bar.total > 0
349
- ? `${AppColors_1.AppColors.grayBorderSecondary}40`
350
- : `${AppColors_1.AppColors.grayBorderSecondary}40`,
417
+ <react_native_1.Text style={{
418
+ fontFamily: AppFonts_1.AppFonts.interBold,
419
+ fontSize: 10,
420
+ color: AppColors_1.AppColors.primaryBlack,
351
421
  }}>
352
- {bar.total > 0 ? (<>
353
- {bar.ecomHeight > 0 && (<react_native_1.View style={{
354
- height: bar.ecomHeight,
355
- backgroundColor: AppColors_1.AppColors.amber500,
356
- }}/>)}
357
- {bar.screenHeight > 0 && (<react_native_1.View style={{
358
- height: bar.screenHeight,
359
- backgroundColor: AppColors_1.AppColors.sky500,
360
- }}/>)}
361
- {bar.sysHeight > 0 && (<react_native_1.View style={{
362
- height: bar.sysHeight,
363
- backgroundColor: AppColors_1.AppColors.purple,
364
- }}/>)}
365
- {bar.custHeight > 0 && (<react_native_1.View style={{
366
- height: bar.custHeight,
367
- backgroundColor: AppColors_1.AppColors.brandPurple,
368
- }}/>)}
369
- </>) : (<react_native_1.View style={{
370
- height: 2.5,
371
- backgroundColor: `${AppColors_1.AppColors.grayBorderSecondary}80`,
372
- }}/>)}
373
- </react_native_1.View>
374
- </react_native_1.View>))}
375
- </react_native_1.View>
422
+ {t('analytics.selectedBucket', {
423
+ time: selectedBucket.ageLabel,
424
+ count: selectedBucket.total,
425
+ })}
426
+ </react_native_1.Text>
427
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
428
+ {selectedBucket.ecommerce > 0 && (<react_native_1.Text style={{ fontSize: 9, fontFamily: AppFonts_1.AppFonts.interBold, color: AppColors_1.AppColors.amber700 }}>
429
+ Ecom: {selectedBucket.ecommerce}
430
+ </react_native_1.Text>)}
431
+ {selectedBucket.page_view > 0 && (<react_native_1.Text style={{ fontSize: 9, fontFamily: AppFonts_1.AppFonts.interBold, color: AppColors_1.AppColors.sky500 }}>
432
+ Screen: {selectedBucket.page_view}
433
+ </react_native_1.Text>)}
434
+ {selectedBucket.custom > 0 && (<react_native_1.Text style={{ fontSize: 9, fontFamily: AppFonts_1.AppFonts.interBold, color: AppColors_1.AppColors.brandPurple }}>
435
+ Custom: {selectedBucket.custom}
436
+ </react_native_1.Text>)}
437
+ </react_native_1.View>
438
+ </react_native_1.View>)}
376
439
 
377
440
  {/* Timeline Axis Labels */}
378
441
  <react_native_1.View style={{
379
442
  flexDirection: 'row',
380
443
  justifyContent: 'space-between',
381
444
  marginTop: 4,
382
- paddingHorizontal: 2,
445
+ paddingHorizontal: 4,
383
446
  }}>
384
447
  <react_native_1.Text style={{
385
448
  fontFamily: AppFonts_1.AppFonts.interMedium,
386
- fontSize: 8,
449
+ fontSize: 8.5,
387
450
  color: AppColors_1.AppColors.grayTextWeak,
388
451
  }}>
389
- -30 min
452
+ {t('analytics.time30mAgo')}
390
453
  </react_native_1.Text>
391
454
  <react_native_1.Text style={{
392
455
  fontFamily: AppFonts_1.AppFonts.interMedium,
393
- fontSize: 8,
456
+ fontSize: 8.5,
394
457
  color: AppColors_1.AppColors.grayTextWeak,
395
458
  }}>
396
- -20 min
459
+ {t('analytics.time20mAgo')}
397
460
  </react_native_1.Text>
398
461
  <react_native_1.Text style={{
399
462
  fontFamily: AppFonts_1.AppFonts.interMedium,
400
- fontSize: 8,
463
+ fontSize: 8.5,
401
464
  color: AppColors_1.AppColors.grayTextWeak,
402
465
  }}>
403
- -10 min
466
+ {t('analytics.time10mAgo')}
404
467
  </react_native_1.Text>
405
468
  <react_native_1.Text style={{
406
469
  fontFamily: AppFonts_1.AppFonts.interBold,
407
- fontSize: 8,
470
+ fontSize: 8.5,
408
471
  color: AppColors_1.AppColors.brandPurple,
409
472
  }}>
410
- NOW
473
+ {t('analytics.timeNow')}
411
474
  </react_native_1.Text>
412
475
  </react_native_1.View>
413
476
  </react_native_1.View>
@@ -686,26 +749,26 @@ const AnalyticsHeader = react_1.default.memo(() => {
686
749
  <react_native_1.View style={styles_1.default.analyticsStatsRow}>
687
750
  <react_native_1.View style={styles_1.default.analyticsStatBox}>
688
751
  <react_native_1.Text style={styles_1.default.analyticsStatValue}>{totalEvents}</react_native_1.Text>
689
- <react_native_1.Text style={styles_1.default.analyticsStatLabel}>Events</react_native_1.Text>
752
+ <react_native_1.Text style={styles_1.default.analyticsStatLabel}>{t('analytics.eventCount', { count: totalEvents })}</react_native_1.Text>
690
753
  </react_native_1.View>
691
754
  <react_native_1.View style={styles_1.default.analyticsStatBox}>
692
755
  <react_native_1.Text style={styles_1.default.analyticsStatValue}>
693
756
  {Object.keys(userProperties).length}
694
757
  </react_native_1.Text>
695
- <react_native_1.Text style={styles_1.default.analyticsStatLabel}>User Props</react_native_1.Text>
758
+ <react_native_1.Text style={styles_1.default.analyticsStatLabel}>{t('analytics.props')}</react_native_1.Text>
696
759
  </react_native_1.View>
697
760
  <react_native_1.View style={styles_1.default.analyticsStatBox}>
698
761
  <react_native_1.Text style={styles_1.default.analyticsStatValue}>
699
762
  {Object.keys(defaultParams).length}
700
763
  </react_native_1.Text>
701
- <react_native_1.Text style={styles_1.default.analyticsStatLabel}>Defaults</react_native_1.Text>
764
+ <react_native_1.Text style={styles_1.default.analyticsStatLabel}>{t('analytics.defaultParameters')}</react_native_1.Text>
702
765
  </react_native_1.View>
703
766
  </react_native_1.View>
704
767
 
705
768
  {/* Details Section */}
706
769
  {(hasUserProps || hasDefaultParams) && (<react_native_1.View style={styles_1.default.analyticsHeaderDetails}>
707
770
  {hasUserProps && (<react_native_1.View style={{ marginBottom: 10 }}>
708
- <react_native_1.Text style={styles_1.default.detailsGroupTitle}>Active User Properties</react_native_1.Text>
771
+ <react_native_1.Text style={styles_1.default.detailsGroupTitle}>{t('analytics.userProperties')}</react_native_1.Text>
709
772
  {Object.entries(userProperties).map(([k, v]) => (<react_native_1.View key={k} style={styles_1.default.detailsRow}>
710
773
  <react_native_1.Text style={styles_1.default.detailsKey} selectable={true}>{k}</react_native_1.Text>
711
774
  <react_native_1.Text style={styles_1.default.detailsValue} selectable={true}>{String(v)}</react_native_1.Text>
@@ -713,7 +776,7 @@ const AnalyticsHeader = react_1.default.memo(() => {
713
776
  </react_native_1.View>)}
714
777
 
715
778
  {hasDefaultParams && (<react_native_1.View>
716
- <react_native_1.Text style={styles_1.default.detailsGroupTitle}>Default Event Parameters</react_native_1.Text>
779
+ <react_native_1.Text style={styles_1.default.detailsGroupTitle}>{t('analytics.defaultParameters')}</react_native_1.Text>
717
780
  {Object.entries(defaultParams).map(([k, v]) => (<react_native_1.View key={k} style={styles_1.default.detailsRow}>
718
781
  <react_native_1.Text style={styles_1.default.detailsKey} selectable={true}>{k}</react_native_1.Text>
719
782
  <react_native_1.Text style={styles_1.default.detailsValue} selectable={true}>{String(v)}</react_native_1.Text>
@@ -724,6 +787,7 @@ const AnalyticsHeader = react_1.default.memo(() => {
724
787
  </react_native_1.View>);
725
788
  });
726
789
  const AnalyticsTab = react_1.default.memo(() => {
790
+ const { t } = (0, i18n_1.useTranslation)();
727
791
  const { filteredAnalyticsEvents, analyticsSearch, setAnalyticsSearch, handleDelete, selectedEvent, setSelectedEvent, newEventIds, logRouteMapRef, isAnalyticsLayoutReady, setIsAnalyticsLayoutReady, isAnalyticsPaused, setIsAnalyticsPaused, isAnalyticsFilterApplied, } = (0, InspectorContext_1.useInspector)();
728
792
  const [isFilterModalOpen, setIsFilterModalOpen] = (0, react_1.useState)(false);
729
793
  const keyExtractor = (0, react_1.useCallback)((item, index) => item?.id?.toString() ?? index.toString(), []);
@@ -43,5 +43,6 @@ export interface TreeNode {
43
43
  fileCount: number;
44
44
  children: TreeNode[];
45
45
  }
46
+ export declare const downloadBundleFile: (file: BundleFileItem, scriptURL?: string) => Promise<void>;
46
47
  declare const BundleTab: React.MemoExoticComponent<() => React.JSX.Element>;
47
48
  export default BundleTab;