react-native-inapp-inspector 2.2.9 → 2.3.1

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 (105) hide show
  1. package/dist/commonjs/components/AppHeaderLogo.js +45 -12
  2. package/dist/commonjs/components/BrandSquareIcon.js +92 -49
  3. package/dist/commonjs/components/EmptyState.d.ts +7 -2
  4. package/dist/commonjs/components/EmptyState.js +11 -5
  5. package/dist/commonjs/components/Inspector/AnalyticsTab.js +29 -18
  6. package/dist/commonjs/components/Inspector/ConsoleTab.js +6 -1
  7. package/dist/commonjs/components/Inspector/CrashDetail.js +43 -9
  8. package/dist/commonjs/components/Inspector/CrashTab.js +34 -3
  9. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +80 -16
  10. package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -3
  11. package/dist/commonjs/components/Inspector/MainScreen.js +7 -11
  12. package/dist/commonjs/components/Inspector/NetworkDetail.js +3 -2
  13. package/dist/commonjs/components/Inspector/NetworkTab.js +103 -4
  14. package/dist/commonjs/components/Inspector/ReduxTab.js +19 -3
  15. package/dist/commonjs/components/Inspector/SettingsPanel.js +4 -4
  16. package/dist/commonjs/components/Inspector/StorageTab.js +123 -92
  17. package/dist/commonjs/components/JsonViewer.js +2 -0
  18. package/dist/commonjs/components/MetaAccordion.js +15 -3
  19. package/dist/commonjs/components/SkeletonPlaceholder.d.ts +6 -0
  20. package/dist/commonjs/components/SkeletonPlaceholder.js +208 -0
  21. package/dist/commonjs/constants/version.d.ts +1 -1
  22. package/dist/commonjs/constants/version.js +1 -1
  23. package/dist/commonjs/customHooks/networkLogger.d.ts +3 -0
  24. package/dist/commonjs/customHooks/networkLogger.js +10 -1
  25. package/dist/commonjs/customHooks/storageInspector.d.ts +2 -2
  26. package/dist/commonjs/customHooks/storageInspector.js +17 -13
  27. package/dist/commonjs/helpers/index.d.ts +6 -0
  28. package/dist/commonjs/helpers/index.js +196 -6
  29. package/dist/commonjs/helpers/searchQueryParser.js +62 -20
  30. package/dist/commonjs/i18n/index.d.ts +13 -0
  31. package/dist/commonjs/i18n/index.js +35 -2
  32. package/dist/commonjs/index.d.ts +3 -0
  33. package/dist/commonjs/index.js +108 -35
  34. package/dist/commonjs/styles/AppColors.d.ts +4 -0
  35. package/dist/commonjs/styles/AppColors.js +11 -1
  36. package/dist/commonjs/styles/AppFonts.d.ts +11 -0
  37. package/dist/commonjs/styles/AppFonts.js +11 -1
  38. package/dist/commonjs/types/interfaces.d.ts +2 -2
  39. package/dist/esm/components/AppHeaderLogo.js +45 -12
  40. package/dist/esm/components/BrandSquareIcon.js +92 -49
  41. package/dist/esm/components/EmptyState.d.ts +7 -2
  42. package/dist/esm/components/EmptyState.js +11 -5
  43. package/dist/esm/components/Inspector/AnalyticsTab.js +30 -19
  44. package/dist/esm/components/Inspector/ConsoleTab.js +6 -1
  45. package/dist/esm/components/Inspector/CrashDetail.js +43 -9
  46. package/dist/esm/components/Inspector/CrashTab.js +34 -3
  47. package/dist/esm/components/Inspector/DeviceInfoTab.js +80 -16
  48. package/dist/esm/components/Inspector/InspectorHeader.js +17 -4
  49. package/dist/esm/components/Inspector/MainScreen.js +8 -12
  50. package/dist/esm/components/Inspector/NetworkDetail.js +3 -2
  51. package/dist/esm/components/Inspector/NetworkTab.js +103 -4
  52. package/dist/esm/components/Inspector/ReduxTab.js +19 -3
  53. package/dist/esm/components/Inspector/SettingsPanel.js +4 -4
  54. package/dist/esm/components/Inspector/StorageTab.js +124 -93
  55. package/dist/esm/components/JsonViewer.js +2 -0
  56. package/dist/esm/components/MetaAccordion.js +15 -3
  57. package/dist/esm/components/SkeletonPlaceholder.d.ts +6 -0
  58. package/dist/esm/components/SkeletonPlaceholder.js +173 -0
  59. package/dist/esm/constants/version.d.ts +1 -1
  60. package/dist/esm/constants/version.js +1 -1
  61. package/dist/esm/customHooks/networkLogger.d.ts +3 -0
  62. package/dist/esm/customHooks/networkLogger.js +8 -0
  63. package/dist/esm/customHooks/storageInspector.d.ts +2 -2
  64. package/dist/esm/customHooks/storageInspector.js +17 -13
  65. package/dist/esm/helpers/index.d.ts +6 -0
  66. package/dist/esm/helpers/index.js +193 -5
  67. package/dist/esm/helpers/searchQueryParser.js +62 -20
  68. package/dist/esm/i18n/index.d.ts +13 -0
  69. package/dist/esm/i18n/index.js +33 -3
  70. package/dist/esm/index.d.ts +3 -0
  71. package/dist/esm/index.js +97 -37
  72. package/dist/esm/styles/AppColors.d.ts +4 -0
  73. package/dist/esm/styles/AppColors.js +9 -0
  74. package/dist/esm/styles/AppFonts.d.ts +11 -0
  75. package/dist/esm/styles/AppFonts.js +9 -0
  76. package/dist/esm/types/interfaces.d.ts +2 -2
  77. package/package.json +1 -1
  78. package/src/components/AppHeaderLogo.tsx +46 -12
  79. package/src/components/BrandSquareIcon.tsx +127 -78
  80. package/src/components/EmptyState.tsx +27 -5
  81. package/src/components/Inspector/AnalyticsTab.tsx +48 -27
  82. package/src/components/Inspector/ConsoleTab.tsx +10 -0
  83. package/src/components/Inspector/CrashDetail.tsx +65 -9
  84. package/src/components/Inspector/CrashTab.tsx +41 -3
  85. package/src/components/Inspector/DeviceInfoTab.tsx +87 -16
  86. package/src/components/Inspector/InspectorHeader.tsx +24 -4
  87. package/src/components/Inspector/MainScreen.tsx +7 -11
  88. package/src/components/Inspector/NetworkDetail.tsx +4 -4
  89. package/src/components/Inspector/NetworkTab.tsx +129 -4
  90. package/src/components/Inspector/ReduxTab.tsx +26 -8
  91. package/src/components/Inspector/SettingsPanel.tsx +4 -4
  92. package/src/components/Inspector/StorageTab.tsx +191 -117
  93. package/src/components/JsonViewer.tsx +2 -0
  94. package/src/components/MetaAccordion.tsx +18 -3
  95. package/src/components/SkeletonPlaceholder.tsx +206 -0
  96. package/src/constants/version.ts +1 -1
  97. package/src/customHooks/networkLogger.ts +15 -0
  98. package/src/customHooks/storageInspector.ts +18 -14
  99. package/src/helpers/index.ts +213 -5
  100. package/src/helpers/searchQueryParser.ts +63 -20
  101. package/src/i18n/index.ts +38 -3
  102. package/src/index.tsx +124 -37
  103. package/src/styles/AppColors.ts +9 -0
  104. package/src/styles/AppFonts.ts +16 -0
  105. package/src/types/interfaces.ts +2 -2
@@ -3,72 +3,115 @@ import Svg, { Circle, Path, G, Defs, LinearGradient, RadialGradient, Stop, Rect,
3
3
  export const BrandSquareIcon = ({ size = 56 }) => {
4
4
  return (<Svg width={size} height={size} viewBox="0 0 256 256" fill="none">
5
5
  <Defs>
6
+ {/* App Tile Background - Crisp Royal Deep Violet to Midnight */}
6
7
  <LinearGradient id="bs_tile" x1="0" y1="0" x2="256" y2="256" gradientUnits="userSpaceOnUse">
7
- <Stop offset="0" stopColor="#1E1B4B"/>
8
- <Stop offset="1" stopColor="#0F172A"/>
8
+ <Stop offset="0%" stopColor="#1E1B4B"/>
9
+ <Stop offset="50%" stopColor="#18182F"/>
10
+ <Stop offset="100%" stopColor="#0B0F19"/>
9
11
  </LinearGradient>
10
- <LinearGradient id="bs_beam" x1="0" y1="0" x2="256" y2="256" gradientUnits="userSpaceOnUse">
11
- <Stop offset="0" stopColor="#818CF8"/>
12
- <Stop offset="0.5" stopColor="#A855F7"/>
13
- <Stop offset="1" stopColor="#EC4899"/>
12
+
13
+ {/* Outer Neon Cyber Border */}
14
+ <LinearGradient id="bs_border" x1="0" y1="0" x2="256" y2="256" gradientUnits="userSpaceOnUse">
15
+ <Stop offset="0%" stopColor="#818CF8" stopOpacity={0.9}/>
16
+ <Stop offset="45%" stopColor="#C084FC" stopOpacity={0.8}/>
17
+ <Stop offset="80%" stopColor="#F472B6" stopOpacity={0.85}/>
18
+ <Stop offset="100%" stopColor="#38BDF8" stopOpacity={0.9}/>
19
+ </LinearGradient>
20
+
21
+ {/* Ambient Top Glow */}
22
+ <RadialGradient id="bs_top_glow" cx="50%" cy="15%" r="65%">
23
+ <Stop offset="0%" stopColor="#818CF8" stopOpacity={0.35}/>
24
+ <Stop offset="60%" stopColor="#A855F7" stopOpacity={0.12}/>
25
+ <Stop offset="100%" stopColor="#1E1B4B" stopOpacity={0}/>
26
+ </RadialGradient>
27
+
28
+ {/* Owl Outer Body Gradient - High Contrast */}
29
+ <LinearGradient id="bs_body" x1="64" y1="40" x2="192" y2="220" gradientUnits="userSpaceOnUse">
30
+ <Stop offset="0%" stopColor="#3730A3"/>
31
+ <Stop offset="50%" stopColor="#2E1065"/>
32
+ <Stop offset="100%" stopColor="#17123A"/>
14
33
  </LinearGradient>
15
- <LinearGradient id="bs_body" x1="0" y1="0" x2="0" y2="256" gradientUnits="userSpaceOnUse">
16
- <Stop offset="0" stopColor="#312E81"/>
17
- <Stop offset="1" stopColor="#1E1B4B"/>
34
+
35
+ {/* Neon Cyber Beam Stroke */}
36
+ <LinearGradient id="bs_beam" x1="40" y1="40" x2="220" y2="220" gradientUnits="userSpaceOnUse">
37
+ <Stop offset="0%" stopColor="#67E8F9"/>
38
+ <Stop offset="35%" stopColor="#818CF8"/>
39
+ <Stop offset="70%" stopColor="#C084FC"/>
40
+ <Stop offset="100%" stopColor="#F472B6"/>
18
41
  </LinearGradient>
19
- <RadialGradient id="bs_iris" cx="40%" cy="40%" r="60%">
20
- <Stop offset="0" stopColor="#FDE047"/>
21
- <Stop offset="0.7" stopColor="#F59E0B"/>
22
- <Stop offset="1" stopColor="#D97706"/>
42
+
43
+ {/* Eyes Radiant Iris */}
44
+ <RadialGradient id="bs_iris" cx="38%" cy="36%" r="65%">
45
+ <Stop offset="0%" stopColor="#FEF08A"/>
46
+ <Stop offset="40%" stopColor="#FBBF24"/>
47
+ <Stop offset="80%" stopColor="#F59E0B"/>
48
+ <Stop offset="100%" stopColor="#D97706"/>
23
49
  </RadialGradient>
24
- <LinearGradient id="bs_beak" x1="0" y1="0" x2="0" y2="20" gradientUnits="userSpaceOnUse">
25
- <Stop offset="0" stopColor="#FBBF24"/>
26
- <Stop offset="1" stopColor="#F97316"/>
50
+
51
+ {/* Beak Gradient */}
52
+ <LinearGradient id="bs_beak" x1="124" y1="120" x2="132" y2="136" gradientUnits="userSpaceOnUse">
53
+ <Stop offset="0%" stopColor="#FDE047"/>
54
+ <Stop offset="100%" stopColor="#EA580C"/>
27
55
  </LinearGradient>
56
+
57
+ {/* Diagnostic Lens Glass Flare */}
58
+ <RadialGradient id="bs_lens" cx="40%" cy="35%" r="65%">
59
+ <Stop offset="0%" stopColor="#A5F3FC" stopOpacity={0.4}/>
60
+ <Stop offset="50%" stopColor="#38BDF8" stopOpacity={0.18}/>
61
+ <Stop offset="100%" stopColor="#0284C7" stopOpacity={0.05}/>
62
+ </RadialGradient>
28
63
  </Defs>
29
64
 
30
- {/* Rounded App Tile Background */}
31
- <Rect x="8" y="8" width="240" height="240" rx="54" fill="url(#bs_tile)"/>
32
- <Rect x="8" y="8" width="240" height="240" rx="54" fill="none" stroke="url(#bs_beam)" strokeWidth="3" strokeOpacity={0.4}/>
65
+ {/* ── 1. Rounded App Tile Base (Full Edge-to-Edge) ── */}
66
+ <Rect x="2" y="2" width="252" height="252" rx="58" fill="url(#bs_tile)"/>
67
+ <Rect x="2" y="2" width="252" height="252" rx="58" fill="url(#bs_top_glow)"/>
68
+ <Rect x="2" y="2" width="252" height="252" rx="58" fill="none" stroke="url(#bs_border)" strokeWidth="3.5"/>
69
+
70
+ {/* ── 2. Owl Outer Wings (Layered behind) ── */}
71
+ <Path d="M62 120 C42 152 46 194 76 210 C68 178 66 146 80 120 Z" fill="#1E1B4B" stroke="url(#bs_beam)" strokeWidth="3" strokeOpacity={0.75}/>
72
+ <Path d="M194 120 C214 152 210 194 180 210 C188 178 190 146 176 120 Z" fill="#1E1B4B" stroke="url(#bs_beam)" strokeWidth="3" strokeOpacity={0.75}/>
33
73
 
34
- {/* Owl Outer Body Contour */}
35
- <Path d="M64 148 C60 102 72 68 92 56 L100 40 L118 60 Q128 55 138 60 L156 40 L164 56 C184 68 196 102 192 148 C196 178 182 202 150 210 C138 214 118 214 106 210 C74 202 60 178 64 148 Z" fill="url(#bs_body)" stroke="url(#bs_beam)" strokeWidth="4" strokeLinejoin="round"/>
74
+ {/* ── 3. Owl Body Contour ── */}
75
+ <Path d="M58 146 C54 98 68 64 88 52 L98 34 L118 56 Q128 50 138 56 L158 34 L168 52 C188 64 202 98 198 146 C202 180 186 208 152 216 C140 220 116 220 104 216 C70 208 54 180 58 146 Z" fill="url(#bs_body)" stroke="url(#bs_beam)" strokeWidth="4.5" strokeLinejoin="round"/>
36
76
 
37
- {/* Wings */}
38
- <Path d="M74 124 C58 154 60 190 86 204 C79 176 77 148 88 126 Z" fill="#1E1B4B" stroke="#818CF8" strokeWidth="2.5" strokeOpacity={0.6}/>
39
- <Path d="M182 124 C198 154 196 190 170 204 C177 176 179 148 168 126 Z" fill="#1E1B4B" stroke="#818CF8" strokeWidth="2.5" strokeOpacity={0.6}/>
77
+ {/* Inner Ear Highlights */}
78
+ <Path d="M98 42 L112 56 L102 57 Z" fill="#67E8F9" opacity={0.6}/>
79
+ <Path d="M158 42 L144 56 L154 57 Z" fill="#F472B6" opacity={0.6}/>
40
80
 
41
- {/* Belly Screen Plate */}
42
- <Rect x="105" y="160" width="46" height="34" rx="8" fill="#0B0F19" stroke="url(#bs_beam)" strokeWidth="2"/>
43
- {/* Code Emblem on Chest */}
44
- <G stroke="#A5B4FC" strokeWidth="2.8" strokeLinecap="round" strokeLinejoin="round" fill="none">
45
- <Path d="M120 171 L114 177 L120 183"/>
46
- <Path d="M136 171 L142 177 L136 183"/>
47
- <Path d="M130 169 L126 185" stroke="#EC4899"/>
81
+ {/* ── 4. Chest Terminal & Code Braces ── */}
82
+ <Rect x="98" y="162" width="60" height="38" rx="10" fill="#050811" stroke="url(#bs_beam)" strokeWidth="2.5"/>
83
+ <G strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" fill="none">
84
+ <Path d="M116 174 L108 181 L116 188" stroke="#38BDF8"/>
85
+ <Path d="M140 174 L148 181 L140 188" stroke="#38BDF8"/>
86
+ <Path d="M131 171 L125 191" stroke="#F43F5E"/>
48
87
  </G>
49
88
 
50
- {/* Facial Disc & Mask */}
51
- <Path d="M128 92 C148 70 186 78 186 108 C186 134 160 152 128 152 C96 152 70 134 70 108 C70 78 108 70 128 92 Z" fill="#2E1065" stroke="#818CF8" strokeWidth="2" strokeOpacity={0.6}/>
89
+ {/* ── 5. Facial Mask Plate ── */}
90
+ <Path d="M128 88 C152 64 192 72 192 104 C192 132 162 152 128 152 C94 152 64 132 64 104 C64 72 104 64 128 88 Z" fill="#1E1B4B" stroke="url(#bs_beam)" strokeWidth="2.8"/>
91
+
92
+ {/* ── 6. Right Eye (Glowing Owl Eye) ── */}
93
+ <Circle cx="156" cy="106" r="19" fill="url(#bs_iris)" stroke="#0F172A" strokeWidth="2.5"/>
94
+ <Circle cx="156" cy="106" r="9.5" fill="#0B0F19"/>
95
+ <Circle cx="159.5" cy="102.5" r="3.5" fill="#FFFFFF"/>
96
+ <Circle cx="153" cy="109.5" r="1.8" fill="#FFFFFF" opacity={0.85}/>
52
97
 
53
- {/* Right Eye (Normal Cute Eye) */}
54
- <Circle cx="154" cy="108" r="17" fill="url(#bs_iris)" stroke="#0F172A" strokeWidth="2"/>
55
- <Circle cx="154" cy="108" r="8.5" fill="#0F172A"/>
56
- <Circle cx="157" cy="105" r="3" fill="#FFFFFF"/>
57
- <Circle cx="151" cy="111" r="1.5" fill="#FFFFFF" opacity={0.8}/>
98
+ {/* ── 7. Left Eye (Diagnostic Magnifier Lens) ── */}
99
+ {/* Magnifier Glass Glow */}
100
+ <Circle cx="94" cy="104" r="30" fill="url(#bs_lens)" stroke="url(#bs_beam)" strokeWidth="6"/>
101
+ <Line x1="72" y1="126" x2="48" y2="152" stroke="#0B0F19" strokeWidth="13" strokeLinecap="round"/>
102
+ <Line x1="72" y1="126" x2="48" y2="152" stroke="url(#bs_beam)" strokeWidth="8" strokeLinecap="round"/>
58
103
 
59
- {/* Left Eye (Diagnostic Magnifier Lens) */}
60
- <Circle cx="96" cy="104" r="20" fill="url(#bs_iris)" stroke="#0F172A" strokeWidth="2"/>
61
- <Circle cx="96" cy="104" r="10" fill="#0F172A"/>
62
- <Circle cx="99.5" cy="100.5" r="3.5" fill="#FFFFFF"/>
63
- <Circle cx="92" cy="107" r="1.8" fill="#FFFFFF" opacity={0.8}/>
104
+ {/* Eye Inside Magnifier */}
105
+ <Circle cx="94" cy="104" r="21" fill="url(#bs_iris)" stroke="#0F172A" strokeWidth="2.5"/>
106
+ <Circle cx="94" cy="104" r="10.5" fill="#0B0F19"/>
107
+ <Circle cx="98" cy="100" r="4" fill="#FFFFFF"/>
108
+ <Circle cx="90.5" cy="107.5" r="2" fill="#FFFFFF" opacity={0.85}/>
64
109
 
65
- {/* Magnifier Glass Ring & Handle */}
66
- <Line x1="76" y1="124" x2="55" y2="148" stroke="#0F172A" strokeWidth="12" strokeLinecap="round"/>
67
- <Line x1="76" y1="124" x2="55" y2="148" stroke="url(#bs_beam)" strokeWidth="7" strokeLinecap="round"/>
68
- <Circle cx="96" cy="104" r="28" fill="#38BDF8" fillOpacity={0.12} stroke="url(#bs_beam)" strokeWidth="6"/>
110
+ {/* Lens Reflection Highlight */}
111
+ <Path d="M74 94 A26 26 0 0 1 106 78" stroke="#FFFFFF" strokeWidth="3" strokeLinecap="round" opacity={0.65} fill="none"/>
69
112
 
70
- {/* Beak */}
71
- <Path d="M123.5 123 Q128 121 132.5 123 Q131 132 128 134.5 Q125 132 123.5 123 Z" fill="url(#bs_beak)"/>
113
+ {/* ── 8. Beak ── */}
114
+ <Path d="M123 120 Q128 118 133 120 Q131.5 133 128 137 Q124.5 133 123 120 Z" fill="url(#bs_beak)" stroke="#78350F" strokeWidth="1"/>
72
115
  </Svg>);
73
116
  };
74
117
  export default BrandSquareIcon;
@@ -1,5 +1,10 @@
1
1
  import React from 'react';
2
- declare const EmptyState: React.NamedExoticComponent<{
2
+ interface EmptyStateProps {
3
3
  isSearch?: boolean;
4
- }>;
4
+ searchQuery?: string;
5
+ customTitle?: string;
6
+ customSub?: string;
7
+ onClearSearch?: () => void;
8
+ }
9
+ declare const EmptyState: React.NamedExoticComponent<EmptyStateProps>;
5
10
  export default EmptyState;
@@ -8,7 +8,7 @@ import { EmptyRadarIcon } from './NetworkIcons';
8
8
  // Stylesheet
9
9
  import { AppColors } from '../styles/AppColors';
10
10
  import styles from '../styles';
11
- const EmptyState = React.memo(function EmptyState({ isSearch }) {
11
+ const EmptyState = React.memo(function EmptyState({ isSearch, searchQuery, customTitle, customSub, onClearSearch, }) {
12
12
  const iconPulse = useRef(new Animated.Value(1)).current;
13
13
  useEffect(() => {
14
14
  const loop = Animated.loop(Animated.sequence([
@@ -38,13 +38,19 @@ const EmptyState = React.memo(function EmptyState({ isSearch }) {
38
38
  <EmptyRadarIcon color={AppColors.purple} size={32}/>
39
39
  </Animated.View>
40
40
  <Text style={styles.emptyTitle}>
41
- {isSearch ? 'No matching APIs' : 'No network activity'}
41
+ {customTitle || (isSearch ? 'No matching results' : 'No network activity')}
42
42
  </Text>
43
43
  <Text style={styles.emptySub}>
44
- {isSearch
45
- ? 'Try adjusting your filters or search.'
46
- : 'Listening for incoming API calls...'}
44
+ {customSub ||
45
+ (isSearch
46
+ ? searchQuery
47
+ ? `No items matched "${searchQuery}"`
48
+ : 'Try adjusting your filters or search keywords.'
49
+ : 'Listening for incoming API calls...')}
47
50
  </Text>
51
+ {isSearch && onClearSearch && (<TouchableScale style={styles.reloadBtn} onPress={onClearSearch}>
52
+ <Text style={styles.reloadBtnText}>Clear Search & Filters</Text>
53
+ </TouchableScale>)}
48
54
  {!isSearch && (<TouchableScale style={styles.reloadBtn} onPress={handleReload}>
49
55
  <Text style={styles.reloadBtnText}>Reload App</Text>
50
56
  </TouchableScale>)}
@@ -4,6 +4,7 @@ import { animateNextLayout, useInspector } from './InspectorContext';
4
4
  import AnalyticsEventCard from '../AnalyticsEventCard';
5
5
  import AnalyticsFilterModal from './AnalyticsFilterModal';
6
6
  import EndOfListFooter from '../EndOfListFooter';
7
+ import EmptyState from '../EmptyState';
7
8
  import styles from '../../styles';
8
9
  import { AppColors } from '../../styles/AppColors';
9
10
  import { AppFonts } from '../../styles/AppFonts';
@@ -12,7 +13,7 @@ import Svg, { Path, Rect, Line, Circle, G, Defs, LinearGradient as SvgLinearGrad
12
13
  import TouchableScale from '../TouchableScale';
13
14
  import { getCurrentUserId, getCurrentUserProperties, getDefaultEventParameters, getCollectionEnabled, } from '../../customHooks/analyticsLogger';
14
15
  import { getEventCategory, } from '../../helpers';
15
- import { LayersIcon, SearchIcon, ClearIcon, TrashIcon, EmptyRadarIcon, HeaderPauseIcon, FilterIcon, CartIcon, GlobeIcon, BoltIcon, SparkleIcon, PinIcon, MoneyIcon, } from '../NetworkIcons';
16
+ import { LayersIcon, SearchIcon, ClearIcon, TrashIcon, HeaderPauseIcon, FilterIcon, CartIcon, GlobeIcon, BoltIcon, SparkleIcon, PinIcon, MoneyIcon, } from '../NetworkIcons';
16
17
  const AnalyticsHeader = React.memo(() => {
17
18
  const { t } = useTranslation();
18
19
  const { analyticsEvents, filteredAnalyticsEvents, analyticsFilters, setAnalyticsFilters, analyticsHeaderExpanded, setAnalyticsHeaderExpanded, } = useInspector();
@@ -850,9 +851,29 @@ const AnalyticsTab = React.memo(() => {
850
851
  <View style={styles.searchContainer}>
851
852
  <SearchIcon color={AppColors.grayTextWeak} size={16}/>
852
853
  <TextInput placeholder="Search events..." placeholderTextColor={AppColors.grayTextWeak} value={analyticsSearch} onChangeText={setAnalyticsSearch} style={styles.searchInput} autoCorrect={false} autoCapitalize="none"/>
853
- {analyticsSearch.length > 0 && (<Pressable onPress={() => setAnalyticsSearch('')} hitSlop={10} style={styles.clearBtn}>
854
- <ClearIcon color={AppColors.grayTextWeak} size={14}/>
855
- </Pressable>)}
854
+ {analyticsSearch.length > 0 && (<View style={{
855
+ flexDirection: 'row',
856
+ alignItems: 'center',
857
+ gap: 4,
858
+ }}>
859
+ <View style={{
860
+ backgroundColor: `${AppColors.purple}20`,
861
+ borderRadius: 10,
862
+ paddingHorizontal: 6,
863
+ paddingVertical: 1.5,
864
+ }}>
865
+ <Text style={{
866
+ color: AppColors.purple,
867
+ fontSize: 9.5,
868
+ fontFamily: AppFonts.interBold,
869
+ }}>
870
+ {filteredAnalyticsEvents.length}
871
+ </Text>
872
+ </View>
873
+ <Pressable onPress={() => setAnalyticsSearch('')} hitSlop={10} style={styles.clearBtn}>
874
+ <ClearIcon color={AppColors.grayTextWeak} size={13}/>
875
+ </Pressable>
876
+ </View>)}
856
877
  </View>
857
878
  <View style={styles.toolbarRight}>
858
879
  <TouchableOpacity style={[
@@ -907,21 +928,11 @@ const AnalyticsTab = React.memo(() => {
907
928
  <AnalyticsFilterModal visible={isFilterModalOpen} onClose={() => setIsFilterModalOpen(false)}/>
908
929
 
909
930
  <View style={{ flex: 1 }} onLayout={() => setIsAnalyticsLayoutReady(true)}>
910
- {isAnalyticsLayoutReady ? (<FlatList data={filteredAnalyticsEvents} keyExtractor={keyExtractor} ListHeaderComponent={AnalyticsHeader} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<View style={styles.emptyContainer}>
911
- <View style={styles.emptyIconWrap}>
912
- <EmptyRadarIcon color={AppColors.purple} size={32}/>
913
- </View>
914
- <Text style={styles.emptyTitle}>
915
- {analyticsSearch.length > 0
916
- ? 'No matching events'
917
- : 'No analytics events yet'}
918
- </Text>
919
- <Text style={styles.emptySub}>
920
- {analyticsSearch.length > 0
921
- ? 'Try adjusting your search.'
922
- : 'Call setupAnalyticsLogger(analytics()) at app start.'}
923
- </Text>
924
- </View>} ListFooterComponent={filteredAnalyticsEvents.length > 0 ? (<EndOfListFooter count={filteredAnalyticsEvents.length} label="events"/>) : null} contentContainerStyle={[
931
+ {isAnalyticsLayoutReady ? (<FlatList data={filteredAnalyticsEvents} keyExtractor={keyExtractor} ListHeaderComponent={AnalyticsHeader} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={analyticsSearch.length > 0} searchQuery={analyticsSearch} customTitle={analyticsSearch.length > 0
932
+ ? 'No matching analytics events'
933
+ : 'No analytics events yet'} customSub={analyticsSearch.length > 0
934
+ ? `No events matched "${analyticsSearch}"`
935
+ : 'Call setupAnalyticsLogger(analytics()) at app start.'} onClearSearch={() => setAnalyticsSearch('')}/>} ListFooterComponent={filteredAnalyticsEvents.length > 0 ? (<EndOfListFooter count={filteredAnalyticsEvents.length} label="events"/>) : null} contentContainerStyle={[
925
936
  styles.listContent,
926
937
  filteredAnalyticsEvents.length === 0 && {
927
938
  flexGrow: 1,
@@ -480,7 +480,12 @@ const ConsoleTab = React.memo(() => {
480
480
  </ScrollView>
481
481
  </View>
482
482
 
483
- <FlatList data={filteredConsoleLogs} keyExtractor={keyExtractor} ListHeaderComponent={listHeader} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={logSearch.length > 0 || logFilters.size > 0}/>} ListFooterComponent={filteredConsoleLogs.length > 0 ? (<EndOfListFooter count={filteredConsoleLogs.length} label="logs"/>) : null} contentContainerStyle={[
483
+ <FlatList data={filteredConsoleLogs} keyExtractor={keyExtractor} ListHeaderComponent={listHeader} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={logSearch.length > 0 || logFilters.size > 0} searchQuery={logSearch} customTitle={logSearch.length > 0
484
+ ? 'No matching console logs'
485
+ : 'No console logs'} onClearSearch={() => {
486
+ setLogSearch('');
487
+ setLogFilters(new Set());
488
+ }}/>} ListFooterComponent={filteredConsoleLogs.length > 0 ? (<EndOfListFooter count={filteredConsoleLogs.length} label="logs"/>) : null} contentContainerStyle={[
484
489
  styles.listContent,
485
490
  filteredConsoleLogs.length === 0 && { flexGrow: 1 },
486
491
  ]} keyboardShouldPersistTaps="handled"/>
@@ -6,6 +6,7 @@ import TouchableScale from '../TouchableScale';
6
6
  import SegmentedTabs from '../SegmentedTabs';
7
7
  import HighlightText from '../HighlightText';
8
8
  import JsonViewer from '../JsonViewer';
9
+ import CopyButton from '../CopyButton';
9
10
  import { AppColors } from '../../styles/AppColors';
10
11
  import { AppFonts } from '../../styles/AppFonts';
11
12
  import { exportCrashReport, parseCrashStackTrace, } from '../../customHooks/crashHandler';
@@ -328,9 +329,20 @@ const CrashDetail = React.memo(() => {
328
329
  {activeSubTab === 'diagnostics' && (<View style={{ gap: 12 }}>
329
330
  {/* Device & OS Diagnostics Card */}
330
331
  <View style={localStyles.sectionCard}>
331
- <View style={localStyles.sectionCardHeader}>
332
- <GlobeIcon color={AppColors.purple} size={14}/>
333
- <Text style={localStyles.sectionCardTitle}>{t('crash.deviceEnvironment')}</Text>
332
+ <View style={[
333
+ localStyles.sectionCardHeader,
334
+ { justifyContent: 'space-between' },
335
+ ]}>
336
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
337
+ <GlobeIcon color={AppColors.purple} size={14}/>
338
+ <Text style={localStyles.sectionCardTitle}>
339
+ {t('crash.deviceEnvironment')}
340
+ </Text>
341
+ </View>
342
+ <CopyButton value={selectedCrash.deviceInfo || {
343
+ platform: Platform.OS,
344
+ osVersion: String(Platform.Version),
345
+ }} label="Diagnostics"/>
334
346
  </View>
335
347
 
336
348
  <View style={localStyles.diagGrid}>
@@ -380,9 +392,17 @@ const CrashDetail = React.memo(() => {
380
392
 
381
393
  {/* Memory Metrics Card */}
382
394
  {selectedCrash.memoryInfo && (<View style={localStyles.sectionCard}>
383
- <View style={localStyles.sectionCardHeader}>
384
- <LayersIcon color={AppColors.purple} size={14}/>
385
- <Text style={localStyles.sectionCardTitle}>{t('crash.jsHeapMemory')}</Text>
395
+ <View style={[
396
+ localStyles.sectionCardHeader,
397
+ { justifyContent: 'space-between' },
398
+ ]}>
399
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
400
+ <LayersIcon color={AppColors.purple} size={14}/>
401
+ <Text style={localStyles.sectionCardTitle}>
402
+ {t('crash.jsHeapMemory')}
403
+ </Text>
404
+ </View>
405
+ <CopyButton value={selectedCrash.memoryInfo} label="Memory Info"/>
386
406
  </View>
387
407
 
388
408
  <View style={localStyles.diagGrid}>
@@ -405,6 +425,13 @@ const CrashDetail = React.memo(() => {
405
425
 
406
426
  {/* 3. BREADCRUMBS TAB */}
407
427
  {activeSubTab === 'breadcrumbs' && (<View style={{ gap: 10 }}>
428
+ {selectedCrash.breadcrumbs && selectedCrash.breadcrumbs.length > 0 && (<View style={{
429
+ flexDirection: 'row',
430
+ justifyContent: 'flex-end',
431
+ marginBottom: 2,
432
+ }}>
433
+ <CopyButton value={selectedCrash.breadcrumbs} label="All Breadcrumbs"/>
434
+ </View>)}
408
435
  {selectedCrash.breadcrumbs && selectedCrash.breadcrumbs.length > 0 ? (selectedCrash.breadcrumbs.map((b, idx) => (<View key={`crumb_${idx}`} style={localStyles.breadcrumbCard}>
409
436
  <View style={localStyles.breadcrumbHeader}>
410
437
  <View style={localStyles.breadcrumbTag}>
@@ -412,9 +439,16 @@ const CrashDetail = React.memo(() => {
412
439
  {b.type.toUpperCase()}
413
440
  </Text>
414
441
  </View>
415
- <Text style={localStyles.breadcrumbTime}>
416
- {new Date(b.timestamp).toLocaleTimeString()}
417
- </Text>
442
+ <View style={{
443
+ flexDirection: 'row',
444
+ alignItems: 'center',
445
+ gap: 8,
446
+ }}>
447
+ <Text style={localStyles.breadcrumbTime}>
448
+ {new Date(b.timestamp).toLocaleTimeString()}
449
+ </Text>
450
+ <CopyButton value={`${new Date(b.timestamp).toLocaleTimeString()} [${b.type.toUpperCase()}] ${b.message}${b.data ? ' ' + JSON.stringify(b.data) : ''}`} label="Breadcrumb"/>
451
+ </View>
418
452
  </View>
419
453
  <Text style={localStyles.breadcrumbMessage}>{b.message}</Text>
420
454
  {b.data && (<View style={{ marginTop: 6 }}>
@@ -307,9 +307,25 @@ const CrashTab = React.memo(() => {
307
307
  <View style={localStyles.searchInputWrapper}>
308
308
  <SearchIcon color={AppColors.grayTextWeak} size={14}/>
309
309
  <TextInput value={searchQuery} onChangeText={setSearchQuery} placeholder={t('crash.searchPlaceholder')} placeholderTextColor={AppColors.grayTextWeak} style={localStyles.searchInput} autoCapitalize="none" autoCorrect={false}/>
310
- {searchQuery.length > 0 && (<TouchableOpacity onPress={() => setSearchQuery('')} hitSlop={8}>
311
- <ClearIcon color={AppColors.grayTextWeak} size={14}/>
312
- </TouchableOpacity>)}
310
+ {searchQuery.length > 0 && (<View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
311
+ <View style={{
312
+ backgroundColor: `${AppColors.purple}20`,
313
+ borderRadius: 10,
314
+ paddingHorizontal: 6,
315
+ paddingVertical: 1.5,
316
+ }}>
317
+ <Text style={{
318
+ color: AppColors.purple,
319
+ fontSize: 9.5,
320
+ fontFamily: AppFonts.interBold,
321
+ }}>
322
+ {filteredList.length}
323
+ </Text>
324
+ </View>
325
+ <TouchableOpacity onPress={() => setSearchQuery('')} hitSlop={8}>
326
+ <ClearIcon color={AppColors.grayTextWeak} size={14}/>
327
+ </TouchableOpacity>
328
+ </View>)}
313
329
  </View>
314
330
 
315
331
  {/* Crash Filters */}
@@ -381,6 +397,21 @@ const CrashTab = React.memo(() => {
381
397
  ? t('crash.emptySearchSubtitle')
382
398
  : t('crash.emptySubtitle')}
383
399
  </Text>
400
+ {searchQuery.length > 0 && (<TouchableScale onPress={() => setSearchQuery('')} style={{
401
+ marginTop: 10,
402
+ paddingHorizontal: 14,
403
+ paddingVertical: 7,
404
+ borderRadius: 8,
405
+ backgroundColor: AppColors.purple,
406
+ }}>
407
+ <Text style={{
408
+ fontFamily: AppFonts.interBold,
409
+ fontSize: 11.5,
410
+ color: AppColors.white,
411
+ }}>
412
+ Clear Search
413
+ </Text>
414
+ </TouchableScale>)}
384
415
  </ScrollView>) : (<FlatList data={filteredList} keyExtractor={item => item.id} renderItem={renderCard} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} contentContainerStyle={localStyles.listContent} showsVerticalScrollIndicator={false} ListFooterComponent={<EndOfListFooter />}/>)}
385
416
 
386
417
  {/* Filter Modal */}
@@ -21,9 +21,9 @@ const InfoRow = React.memo(({ label, value, copyable = true, badge, subtext, isL
21
21
  styles.infoRow,
22
22
  isLast && { borderBottomWidth: 0 },
23
23
  ]}>
24
- <View style={{ flex: 1, paddingRight: 8 }}>
25
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
26
- <Text style={styles.infoLabel}>{label}</Text>
24
+ <View style={{ flex: 1, paddingRight: 8, minWidth: 0 }}>
25
+ <View style={{ flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', gap: 6 }}>
26
+ <Text style={styles.infoLabel} numberOfLines={2}>{label}</Text>
27
27
  {badge && (<View style={[
28
28
  styles.infoBadge,
29
29
  { backgroundColor: badge.bg, borderColor: `${badge.color}33` },
@@ -33,15 +33,22 @@ const InfoRow = React.memo(({ label, value, copyable = true, badge, subtext, isL
33
33
  </Text>
34
34
  </View>)}
35
35
  </View>
36
- {subtext && <Text style={styles.infoSubtext}>{subtext}</Text>}
36
+ {subtext && <Text style={styles.infoSubtext} numberOfLines={2}>{subtext}</Text>}
37
37
  </View>
38
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
38
+ <View style={{
39
+ flexDirection: 'row',
40
+ alignItems: 'center',
41
+ gap: 6,
42
+ flexShrink: 0,
43
+ maxWidth: '58%',
44
+ justifyContent: 'flex-end',
45
+ }}>
39
46
  <Text style={[
40
47
  styles.infoValue,
41
48
  typeof value === 'boolean' && {
42
49
  color: value ? AppColors.emerald500 : AppColors.errorColor,
43
50
  },
44
- ]} numberOfLines={2} selectable>
51
+ ]} numberOfLines={3} selectable>
45
52
  {displayValue}
46
53
  </Text>
47
54
  {copyable && value !== null && value !== undefined && (<TouchableScale hitSlop={8} onPress={() => {
@@ -348,6 +355,14 @@ export const DeviceInfoTab = React.memo(() => {
348
355
  return true;
349
356
  return text.toLowerCase().includes(search.toLowerCase().trim());
350
357
  };
358
+ const hasAnyMatch = useMemo(() => {
359
+ if (!search.trim())
360
+ return true;
361
+ const query = search.toLowerCase().trim();
362
+ return (JSON.stringify(fullDeviceData).toLowerCase().includes(query) ||
363
+ ipAddress.toLowerCase().includes(query) ||
364
+ pseudoUDID.toLowerCase().includes(query));
365
+ }, [search, fullDeviceData, ipAddress, pseudoUDID]);
351
366
  return (<View style={styles.container}>
352
367
  {/* ─── Top Sub-Tabs Navigation Bar ─── */}
353
368
  <View style={styles.subTabsWrapper}>
@@ -397,11 +412,11 @@ export const DeviceInfoTab = React.memo(() => {
397
412
  <View style={styles.heroIconWrap}>
398
413
  {Platform.OS === 'ios' ? (<AppleIcon size={20} color={AppColors.white}/>) : (<AndroidIcon size={20} color={AppColors.white}/>)}
399
414
  </View>
400
- <View style={{ flex: 1 }}>
401
- <Text style={styles.heroTitle}>
415
+ <View style={{ flex: 1, minWidth: 0 }}>
416
+ <Text style={styles.heroTitle} numberOfLines={1} ellipsizeMode="tail">
402
417
  {deviceMetrics?.deviceModel || Platform.constants?.Model || (Platform.OS === 'ios' ? 'Apple iPhone' : 'Android Device')}
403
418
  </Text>
404
- <Text style={styles.heroSubtitle}>
419
+ <Text style={styles.heroSubtitle} numberOfLines={1} ellipsizeMode="tail">
405
420
  {Platform.OS === 'ios' ? `iOS ${Platform.Version}` : `Android ${Platform.Version} (API ${deviceMetrics?.apiLevel || Platform.Version})`}
406
421
  </Text>
407
422
  </View>
@@ -414,22 +429,22 @@ export const DeviceInfoTab = React.memo(() => {
414
429
  {/* Quick Metrics Strip */}
415
430
  <View style={styles.heroMetricsStrip}>
416
431
  <View style={styles.heroMetricItem}>
417
- <Text style={styles.heroMetricLabel}>IP ADDRESS</Text>
418
- <Text style={styles.heroMetricValue} numberOfLines={1}>
432
+ <Text style={styles.heroMetricLabel} numberOfLines={1} ellipsizeMode="tail">IP ADDRESS</Text>
433
+ <Text style={styles.heroMetricValue} numberOfLines={1} ellipsizeMode="tail">
419
434
  {ipAddress}
420
435
  </Text>
421
436
  </View>
422
437
  <View style={styles.heroMetricDivider}/>
423
438
  <View style={styles.heroMetricItem}>
424
- <Text style={styles.heroMetricLabel}>RAM (USED/TOTAL)</Text>
425
- <Text style={styles.heroMetricValue}>
439
+ <Text style={styles.heroMetricLabel} numberOfLines={1} ellipsizeMode="tail">RAM (USED/TOTAL)</Text>
440
+ <Text style={styles.heroMetricValue} numberOfLines={1} ellipsizeMode="tail">
426
441
  {usedRamMb}/{totalRamMb} MB
427
442
  </Text>
428
443
  </View>
429
444
  <View style={styles.heroMetricDivider}/>
430
445
  <View style={styles.heroMetricItem}>
431
- <Text style={styles.heroMetricLabel}>UPTIME</Text>
432
- <Text style={styles.heroMetricValue}>{deviceUptime}</Text>
446
+ <Text style={styles.heroMetricLabel} numberOfLines={1} ellipsizeMode="tail">UPTIME</Text>
447
+ <Text style={styles.heroMetricValue} numberOfLines={1} ellipsizeMode="tail">{deviceUptime}</Text>
433
448
  </View>
434
449
  </View>
435
450
  </View>
@@ -542,6 +557,18 @@ export const DeviceInfoTab = React.memo(() => {
542
557
  {isMatch('Sandbox Integrity') && (<InfoRow label="App Sandbox File Isolation" value="Enforced by OS Kernel" isLast/>)}
543
558
  </View>)}
544
559
 
560
+ {/* Empty search results state */}
561
+ {search.trim().length > 0 && !hasAnyMatch && (<View style={styles.emptySearchCard}>
562
+ <SearchIcon size={26} color={AppColors.grayTextWeak}/>
563
+ <Text style={styles.emptySearchTitle}>No matching device specifications</Text>
564
+ <Text style={styles.emptySearchSubtitle}>
565
+ No properties matched &ldquo;{search}&rdquo;
566
+ </Text>
567
+ <TouchableScale onPress={() => setSearch('')} style={styles.clearSearchBtn}>
568
+ <Text style={styles.clearSearchBtnText}>Clear Search</Text>
569
+ </TouchableScale>
570
+ </View>)}
571
+
545
572
  <View style={{ height: 48 }}/>
546
573
  </ScrollView>
547
574
  </View>);
@@ -713,6 +740,8 @@ const styles = StyleSheet.create({
713
740
  heroMetricItem: {
714
741
  flex: 1,
715
742
  alignItems: 'center',
743
+ paddingHorizontal: 2,
744
+ minWidth: 0,
716
745
  },
717
746
  heroMetricLabel: {
718
747
  fontFamily: AppFonts.interBold,
@@ -784,7 +813,7 @@ const styles = StyleSheet.create({
784
813
  fontFamily: AppFonts.interBold,
785
814
  fontSize: 12,
786
815
  color: AppColors.primaryBlack,
787
- maxWidth: 180,
816
+ flexShrink: 1,
788
817
  textAlign: 'right',
789
818
  },
790
819
  rowCopyBtn: {
@@ -792,5 +821,40 @@ const styles = StyleSheet.create({
792
821
  borderRadius: 4,
793
822
  backgroundColor: AppColors.grayBackground,
794
823
  },
824
+ emptySearchCard: {
825
+ backgroundColor: AppColors.primaryLight,
826
+ borderRadius: 14,
827
+ borderWidth: 1,
828
+ borderColor: AppColors.grayBorderSecondary,
829
+ padding: 24,
830
+ alignItems: 'center',
831
+ justifyContent: 'center',
832
+ gap: 8,
833
+ marginTop: 8,
834
+ },
835
+ emptySearchTitle: {
836
+ fontFamily: AppFonts.interBold,
837
+ fontSize: 13.5,
838
+ color: AppColors.primaryBlack,
839
+ textAlign: 'center',
840
+ },
841
+ emptySearchSubtitle: {
842
+ fontFamily: AppFonts.interRegular,
843
+ fontSize: 11.5,
844
+ color: AppColors.grayTextWeak,
845
+ textAlign: 'center',
846
+ },
847
+ clearSearchBtn: {
848
+ marginTop: 6,
849
+ paddingHorizontal: 14,
850
+ paddingVertical: 6.5,
851
+ borderRadius: 8,
852
+ backgroundColor: AppColors.purple,
853
+ },
854
+ clearSearchBtnText: {
855
+ fontFamily: AppFonts.interBold,
856
+ fontSize: 11,
857
+ color: AppColors.white,
858
+ },
795
859
  });
796
860
  export default DeviceInfoTab;