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
@@ -60,9 +60,9 @@ const InfoRow = react_1.default.memo(({ label, value, copyable = true, badge, su
60
60
  styles.infoRow,
61
61
  isLast && { borderBottomWidth: 0 },
62
62
  ]}>
63
- <react_native_1.View style={{ flex: 1, paddingRight: 8 }}>
64
- <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
65
- <react_native_1.Text style={styles.infoLabel}>{label}</react_native_1.Text>
63
+ <react_native_1.View style={{ flex: 1, paddingRight: 8, minWidth: 0 }}>
64
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', gap: 6 }}>
65
+ <react_native_1.Text style={styles.infoLabel} numberOfLines={2}>{label}</react_native_1.Text>
66
66
  {badge && (<react_native_1.View style={[
67
67
  styles.infoBadge,
68
68
  { backgroundColor: badge.bg, borderColor: `${badge.color}33` },
@@ -72,15 +72,22 @@ const InfoRow = react_1.default.memo(({ label, value, copyable = true, badge, su
72
72
  </react_native_1.Text>
73
73
  </react_native_1.View>)}
74
74
  </react_native_1.View>
75
- {subtext && <react_native_1.Text style={styles.infoSubtext}>{subtext}</react_native_1.Text>}
75
+ {subtext && <react_native_1.Text style={styles.infoSubtext} numberOfLines={2}>{subtext}</react_native_1.Text>}
76
76
  </react_native_1.View>
77
- <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
77
+ <react_native_1.View style={{
78
+ flexDirection: 'row',
79
+ alignItems: 'center',
80
+ gap: 6,
81
+ flexShrink: 0,
82
+ maxWidth: '58%',
83
+ justifyContent: 'flex-end',
84
+ }}>
78
85
  <react_native_1.Text style={[
79
86
  styles.infoValue,
80
87
  typeof value === 'boolean' && {
81
88
  color: value ? AppColors_1.AppColors.emerald500 : AppColors_1.AppColors.errorColor,
82
89
  },
83
- ]} numberOfLines={2} selectable>
90
+ ]} numberOfLines={3} selectable>
84
91
  {displayValue}
85
92
  </react_native_1.Text>
86
93
  {copyable && value !== null && value !== undefined && (<TouchableScale_1.default hitSlop={8} onPress={() => {
@@ -387,6 +394,14 @@ exports.DeviceInfoTab = react_1.default.memo(() => {
387
394
  return true;
388
395
  return text.toLowerCase().includes(search.toLowerCase().trim());
389
396
  };
397
+ const hasAnyMatch = (0, react_1.useMemo)(() => {
398
+ if (!search.trim())
399
+ return true;
400
+ const query = search.toLowerCase().trim();
401
+ return (JSON.stringify(fullDeviceData).toLowerCase().includes(query) ||
402
+ ipAddress.toLowerCase().includes(query) ||
403
+ pseudoUDID.toLowerCase().includes(query));
404
+ }, [search, fullDeviceData, ipAddress, pseudoUDID]);
390
405
  return (<react_native_1.View style={styles.container}>
391
406
  {/* ─── Top Sub-Tabs Navigation Bar ─── */}
392
407
  <react_native_1.View style={styles.subTabsWrapper}>
@@ -436,11 +451,11 @@ exports.DeviceInfoTab = react_1.default.memo(() => {
436
451
  <react_native_1.View style={styles.heroIconWrap}>
437
452
  {react_native_1.Platform.OS === 'ios' ? (<NetworkIcons_1.AppleIcon size={20} color={AppColors_1.AppColors.white}/>) : (<NetworkIcons_1.AndroidIcon size={20} color={AppColors_1.AppColors.white}/>)}
438
453
  </react_native_1.View>
439
- <react_native_1.View style={{ flex: 1 }}>
440
- <react_native_1.Text style={styles.heroTitle}>
454
+ <react_native_1.View style={{ flex: 1, minWidth: 0 }}>
455
+ <react_native_1.Text style={styles.heroTitle} numberOfLines={1} ellipsizeMode="tail">
441
456
  {deviceMetrics?.deviceModel || react_native_1.Platform.constants?.Model || (react_native_1.Platform.OS === 'ios' ? 'Apple iPhone' : 'Android Device')}
442
457
  </react_native_1.Text>
443
- <react_native_1.Text style={styles.heroSubtitle}>
458
+ <react_native_1.Text style={styles.heroSubtitle} numberOfLines={1} ellipsizeMode="tail">
444
459
  {react_native_1.Platform.OS === 'ios' ? `iOS ${react_native_1.Platform.Version}` : `Android ${react_native_1.Platform.Version} (API ${deviceMetrics?.apiLevel || react_native_1.Platform.Version})`}
445
460
  </react_native_1.Text>
446
461
  </react_native_1.View>
@@ -453,22 +468,22 @@ exports.DeviceInfoTab = react_1.default.memo(() => {
453
468
  {/* Quick Metrics Strip */}
454
469
  <react_native_1.View style={styles.heroMetricsStrip}>
455
470
  <react_native_1.View style={styles.heroMetricItem}>
456
- <react_native_1.Text style={styles.heroMetricLabel}>IP ADDRESS</react_native_1.Text>
457
- <react_native_1.Text style={styles.heroMetricValue} numberOfLines={1}>
471
+ <react_native_1.Text style={styles.heroMetricLabel} numberOfLines={1} ellipsizeMode="tail">IP ADDRESS</react_native_1.Text>
472
+ <react_native_1.Text style={styles.heroMetricValue} numberOfLines={1} ellipsizeMode="tail">
458
473
  {ipAddress}
459
474
  </react_native_1.Text>
460
475
  </react_native_1.View>
461
476
  <react_native_1.View style={styles.heroMetricDivider}/>
462
477
  <react_native_1.View style={styles.heroMetricItem}>
463
- <react_native_1.Text style={styles.heroMetricLabel}>RAM (USED/TOTAL)</react_native_1.Text>
464
- <react_native_1.Text style={styles.heroMetricValue}>
478
+ <react_native_1.Text style={styles.heroMetricLabel} numberOfLines={1} ellipsizeMode="tail">RAM (USED/TOTAL)</react_native_1.Text>
479
+ <react_native_1.Text style={styles.heroMetricValue} numberOfLines={1} ellipsizeMode="tail">
465
480
  {usedRamMb}/{totalRamMb} MB
466
481
  </react_native_1.Text>
467
482
  </react_native_1.View>
468
483
  <react_native_1.View style={styles.heroMetricDivider}/>
469
484
  <react_native_1.View style={styles.heroMetricItem}>
470
- <react_native_1.Text style={styles.heroMetricLabel}>UPTIME</react_native_1.Text>
471
- <react_native_1.Text style={styles.heroMetricValue}>{deviceUptime}</react_native_1.Text>
485
+ <react_native_1.Text style={styles.heroMetricLabel} numberOfLines={1} ellipsizeMode="tail">UPTIME</react_native_1.Text>
486
+ <react_native_1.Text style={styles.heroMetricValue} numberOfLines={1} ellipsizeMode="tail">{deviceUptime}</react_native_1.Text>
472
487
  </react_native_1.View>
473
488
  </react_native_1.View>
474
489
  </react_native_1.View>
@@ -581,6 +596,18 @@ exports.DeviceInfoTab = react_1.default.memo(() => {
581
596
  {isMatch('Sandbox Integrity') && (<InfoRow label="App Sandbox File Isolation" value="Enforced by OS Kernel" isLast/>)}
582
597
  </react_native_1.View>)}
583
598
 
599
+ {/* Empty search results state */}
600
+ {search.trim().length > 0 && !hasAnyMatch && (<react_native_1.View style={styles.emptySearchCard}>
601
+ <NetworkIcons_1.SearchIcon size={26} color={AppColors_1.AppColors.grayTextWeak}/>
602
+ <react_native_1.Text style={styles.emptySearchTitle}>No matching device specifications</react_native_1.Text>
603
+ <react_native_1.Text style={styles.emptySearchSubtitle}>
604
+ No properties matched &ldquo;{search}&rdquo;
605
+ </react_native_1.Text>
606
+ <TouchableScale_1.default onPress={() => setSearch('')} style={styles.clearSearchBtn}>
607
+ <react_native_1.Text style={styles.clearSearchBtnText}>Clear Search</react_native_1.Text>
608
+ </TouchableScale_1.default>
609
+ </react_native_1.View>)}
610
+
584
611
  <react_native_1.View style={{ height: 48 }}/>
585
612
  </react_native_1.ScrollView>
586
613
  </react_native_1.View>);
@@ -752,6 +779,8 @@ const styles = react_native_1.StyleSheet.create({
752
779
  heroMetricItem: {
753
780
  flex: 1,
754
781
  alignItems: 'center',
782
+ paddingHorizontal: 2,
783
+ minWidth: 0,
755
784
  },
756
785
  heroMetricLabel: {
757
786
  fontFamily: AppFonts_1.AppFonts.interBold,
@@ -823,7 +852,7 @@ const styles = react_native_1.StyleSheet.create({
823
852
  fontFamily: AppFonts_1.AppFonts.interBold,
824
853
  fontSize: 12,
825
854
  color: AppColors_1.AppColors.primaryBlack,
826
- maxWidth: 180,
855
+ flexShrink: 1,
827
856
  textAlign: 'right',
828
857
  },
829
858
  rowCopyBtn: {
@@ -831,5 +860,40 @@ const styles = react_native_1.StyleSheet.create({
831
860
  borderRadius: 4,
832
861
  backgroundColor: AppColors_1.AppColors.grayBackground,
833
862
  },
863
+ emptySearchCard: {
864
+ backgroundColor: AppColors_1.AppColors.primaryLight,
865
+ borderRadius: 14,
866
+ borderWidth: 1,
867
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
868
+ padding: 24,
869
+ alignItems: 'center',
870
+ justifyContent: 'center',
871
+ gap: 8,
872
+ marginTop: 8,
873
+ },
874
+ emptySearchTitle: {
875
+ fontFamily: AppFonts_1.AppFonts.interBold,
876
+ fontSize: 13.5,
877
+ color: AppColors_1.AppColors.primaryBlack,
878
+ textAlign: 'center',
879
+ },
880
+ emptySearchSubtitle: {
881
+ fontFamily: AppFonts_1.AppFonts.interRegular,
882
+ fontSize: 11.5,
883
+ color: AppColors_1.AppColors.grayTextWeak,
884
+ textAlign: 'center',
885
+ },
886
+ clearSearchBtn: {
887
+ marginTop: 6,
888
+ paddingHorizontal: 14,
889
+ paddingVertical: 6.5,
890
+ borderRadius: 8,
891
+ backgroundColor: AppColors_1.AppColors.purple,
892
+ },
893
+ clearSearchBtnText: {
894
+ fontFamily: AppFonts_1.AppFonts.interBold,
895
+ fontSize: 11,
896
+ color: AppColors_1.AppColors.white,
897
+ },
834
898
  });
835
899
  exports.default = exports.DeviceInfoTab;
@@ -48,11 +48,26 @@ const AppFonts_1 = require("../../styles/AppFonts");
48
48
  const constants_1 = require("../../constants");
49
49
  const constants_2 = require("../../constants");
50
50
  const helpers_1 = require("../../helpers");
51
+ const NativeInspector_1 = require("../../native/NativeInspector");
51
52
  const UpdateAvailableModal_1 = require("./UpdateAvailableModal");
52
53
  const NetworkIcons_1 = require("../NetworkIcons");
53
54
  const InspectorHeader = react_1.default.memo(() => {
54
55
  const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, settingsPage, setSettingsPage, resetToDefaults, closeModal, detailTitle, activeTab, environment, visible, selectedCrash, setSelectedCrash, } = (0, InspectorContext_1.useInspector)();
55
56
  const [showUpdateModal, setShowUpdateModal] = react_1.default.useState(false);
57
+ const [appVersionString, setAppVersionString] = react_1.default.useState(() => {
58
+ return (0, helpers_1.getAppVersionAndBuild)().formatted;
59
+ });
60
+ react_1.default.useEffect(() => {
61
+ (0, NativeInspector_1.getNativeDeviceMetrics)()
62
+ .then(metrics => {
63
+ if (metrics?.appVersion) {
64
+ const v = metrics.appVersion;
65
+ const b = metrics.appBuild || '1';
66
+ setAppVersionString(`${v} (${b})`);
67
+ }
68
+ })
69
+ .catch(() => { });
70
+ }, []);
56
71
  const envConfig = (0, react_1.useMemo)(() => {
57
72
  const rawEnv = (environment || (__DEV__ ? 'DEV' : 'PROD')).trim();
58
73
  const clean = rawEnv.toUpperCase();
@@ -303,9 +318,7 @@ const InspectorHeader = react_1.default.memo(() => {
303
318
  color: `${AppColors_1.AppColors.white}EB`,
304
319
  letterSpacing: 0.1,
305
320
  }} numberOfLines={1}>
306
- {react_native_1.Platform.OS === 'ios'
307
- ? `iOS ${react_native_1.Platform.Version}`
308
- : `Android ${react_native_1.Platform.Version}`}
321
+ {appVersionString}
309
322
  </react_native_1.Text>
310
323
  </react_native_1.View>
311
324
 
@@ -49,6 +49,7 @@ const LogDetail_1 = __importDefault(require("./LogDetail"));
49
49
  const ConsoleTab_1 = __importDefault(require("./ConsoleTab"));
50
50
  const AnalyticsTab_1 = __importDefault(require("./AnalyticsTab"));
51
51
  const AnalyticsDetail_1 = __importDefault(require("../AnalyticsDetail"));
52
+ const SkeletonPlaceholder_1 = __importDefault(require("../SkeletonPlaceholder"));
52
53
  const ReduxTab_1 = __importDefault(require("./ReduxTab"));
53
54
  const ReduxDetail_1 = __importDefault(require("./ReduxDetail"));
54
55
  const BundleTab_1 = __importDefault(require("./BundleTab"));
@@ -64,7 +65,7 @@ const styles_1 = __importDefault(require("../../styles"));
64
65
  const AppColors_1 = require("../../styles/AppColors");
65
66
  const NavigationTracker_1 = __importDefault(require("./NavigationTracker"));
66
67
  const MainScreen = () => {
67
- const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, selectedCrash, settingsPage, activeTab, isReady, isEnabled, useNativeFab, hasNavigationContext, setNavState, } = (0, InspectorContext_1.useInspector)();
68
+ const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, selectedCrash, settingsPage, activeTab, isReady, enabled, useNativeFab, hasNavigationContext, setNavState, } = (0, InspectorContext_1.useInspector)();
68
69
  const isDetailActive = (activeTab === 'apis' && selected != null) ||
69
70
  (activeTab === 'analytics' && selectedEvent != null) ||
70
71
  (activeTab === 'logs' && selectedLog != null) ||
@@ -106,7 +107,7 @@ const MainScreen = () => {
106
107
  }, [activeTab]);
107
108
  return (<>
108
109
  {(react_native_1.Platform.OS === 'ios' || react_native_1.Platform.OS === 'android') &&
109
- isEnabled &&
110
+ enabled &&
110
111
  !visible &&
111
112
  !useNativeFab && <FabLauncher_1.default />}
112
113
  <react_native_1.Modal visible={visible} animationType={modalAnimationType} transparent statusBarTranslucent={true}>
@@ -126,10 +127,10 @@ const MainScreen = () => {
126
127
  <InspectorHeader_1.default />
127
128
 
128
129
  <react_native_1.View style={{ flex: 1 }}>
129
- {isReady ? (<react_native_1.View style={{ flex: 1 }}>
130
- {/* ─── Horizontal Scrollable Tab Bar inside Content ─── */}
131
- {!isDetailActive && <TabBar_1.default />}
130
+ {/* ─── Horizontal Scrollable Tab Bar inside Content (Always visible) ─── */}
131
+ {!isDetailActive && <TabBar_1.default />}
132
132
 
133
+ {isReady ? (<react_native_1.View style={{ flex: 1 }}>
133
134
  {/* Persistent List Layer - Never unmounted, preserves 100% native scroll with smooth tab transition */}
134
135
  <react_native_1.Animated.View style={[
135
136
  {
@@ -181,12 +182,7 @@ const MainScreen = () => {
181
182
  {activeTab === 'redux' && <ReduxDetail_1.default />}
182
183
  {activeTab === 'crash' && selectedCrash != null && (<CrashDetail_1.default />)}
183
184
  </react_native_1.Animated.View>)}
184
- </react_native_1.View>) : (<react_native_1.View style={styles_1.default.empty}>
185
- <react_native_1.ActivityIndicator size="large" color={AppColors_1.AppColors.purple}/>
186
- <react_native_1.Text style={[styles_1.default.emptySub, { marginTop: 12 }]}>
187
- Loading logs...
188
- </react_native_1.Text>
189
- </react_native_1.View>)}
185
+ </react_native_1.View>) : (<SkeletonPlaceholder_1.default />)}
190
186
 
191
187
  {/* Settings Panel Layer - Rendered on top with smooth slide & spring transition */}
192
188
  {settingsPage !== null && (<react_native_1.Animated.View style={[
@@ -401,8 +401,9 @@ const NetworkDetail = react_1.default.memo(() => {
401
401
  selected.responseHeaders?.['Content-Type']} url={selected.url}/>
402
402
 
403
403
  {(() => {
404
- const routeInfo = logRouteMapRef.current.get(selected.id);
405
- if (!routeInfo || routeInfo.path === 'Navigators')
404
+ const routeInfo = logRouteMapRef.current.get(selected.id) ||
405
+ selected?.routeInfo;
406
+ if (!routeInfo || !routeInfo.path || routeInfo.path === 'Navigators')
406
407
  return null;
407
408
  return <SourcePageCard_1.default routeInfo={routeInfo}/>;
408
409
  })()}
@@ -507,7 +507,7 @@ const NetworkTab = react_1.default.memo(() => {
507
507
  <react_native_1.View style={{
508
508
  backgroundColor: `${AppColors_1.AppColors.purple}20`,
509
509
  borderRadius: 10,
510
- paddingHorizontal: 5,
510
+ paddingHorizontal: 6,
511
511
  paddingVertical: 1.5,
512
512
  }}>
513
513
  <react_native_1.Text style={{
@@ -560,14 +560,104 @@ const NetworkTab = react_1.default.memo(() => {
560
560
  styles_1.default.toolbarBtn,
561
561
  filtersAccordion.isOpen &&
562
562
  styles_1.default.toolbarBtnActive,
563
- ]} onPress={filtersAccordion.toggleOpen} hitSlop={10}>
563
+ ]} onPress={filtersAccordion.toggleOpen} hitSlop={6}>
564
564
  <NetworkIcons_1.FilterIcon color={filtersAccordion.isOpen
565
565
  ? AppColors_1.AppColors.purple
566
- : AppColors_1.AppColors.grayTextStrong} size={18}/>
566
+ : AppColors_1.AppColors.grayTextStrong} size={16}/>
567
+ {(statusFilters.size > 0 ||
568
+ methodFilters.size > 0) && (<react_native_1.View style={styles_1.default.activeFilterDot}/>)}
567
569
  </TouchableScale_1.default>
568
570
  </react_native_1.View>
569
571
  </react_native_1.View>
570
572
 
573
+ {/* Quick Search Scope & Filter Tags Row */}
574
+ <react_native_1.View style={{ paddingBottom: 4 }}>
575
+ <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{
576
+ paddingHorizontal: 12,
577
+ flexDirection: 'row',
578
+ alignItems: 'center',
579
+ gap: 5,
580
+ paddingVertical: 2,
581
+ }}>
582
+ {/* Search Scopes */}
583
+ {SEARCH_SCOPES.map(s => {
584
+ const isActive = searchScope === s.id;
585
+ return (<TouchableScale_1.default key={`scope_${s.id}`} onPress={() => setSearchScope(s.id)} hitSlop={6} style={{
586
+ flexDirection: 'row',
587
+ alignItems: 'center',
588
+ gap: 3.5,
589
+ paddingHorizontal: 7.5,
590
+ paddingVertical: 3.5,
591
+ borderRadius: 6,
592
+ backgroundColor: isActive
593
+ ? AppColors_1.AppColors.purple
594
+ : AppColors_1.AppColors.grayBackground,
595
+ borderWidth: 1,
596
+ borderColor: isActive
597
+ ? AppColors_1.AppColors.purple
598
+ : AppColors_1.AppColors.grayBorderSecondary,
599
+ }}>
600
+ {s.icon(isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.grayTextWeak)}
601
+ <react_native_1.Text style={{
602
+ fontFamily: AppFonts_1.AppFonts.interBold,
603
+ fontSize: 10,
604
+ color: isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.grayText,
605
+ }}>
606
+ {s.label}
607
+ </react_native_1.Text>
608
+ </TouchableScale_1.default>);
609
+ })}
610
+
611
+ <react_native_1.View style={{
612
+ width: 1,
613
+ height: 14,
614
+ backgroundColor: AppColors_1.AppColors.dividerColor,
615
+ marginHorizontal: 3,
616
+ }}/>
617
+
618
+ {/* Quick Query Suggestions */}
619
+ {QUICK_API_QUERY_TAGS.map(q => {
620
+ const isActive = search.includes(q.query);
621
+ return (<TouchableScale_1.default key={`quick_${q.query}`} onPress={() => {
622
+ setSearch(prev => {
623
+ if (prev.includes(q.query)) {
624
+ return prev
625
+ .replace(q.query, '')
626
+ .replace(/\s+/g, ' ')
627
+ .trim();
628
+ }
629
+ return `${prev} ${q.query}`.trim();
630
+ });
631
+ }} hitSlop={6} style={{
632
+ flexDirection: 'row',
633
+ alignItems: 'center',
634
+ gap: 3.5,
635
+ paddingHorizontal: 7.5,
636
+ paddingVertical: 3.5,
637
+ borderRadius: 6,
638
+ backgroundColor: isActive
639
+ ? `${AppColors_1.AppColors.purple}20`
640
+ : AppColors_1.AppColors.grayBackground,
641
+ borderWidth: 1,
642
+ borderColor: isActive
643
+ ? AppColors_1.AppColors.purple
644
+ : AppColors_1.AppColors.grayBorderSecondary,
645
+ }}>
646
+ {q.icon(isActive ? AppColors_1.AppColors.purple : AppColors_1.AppColors.grayTextWeak)}
647
+ <react_native_1.Text style={{
648
+ fontFamily: AppFonts_1.AppFonts.interMedium,
649
+ fontSize: 10,
650
+ color: isActive
651
+ ? AppColors_1.AppColors.purple
652
+ : AppColors_1.AppColors.grayText,
653
+ }}>
654
+ {q.label}
655
+ </react_native_1.Text>
656
+ </TouchableScale_1.default>);
657
+ })}
658
+ </react_native_1.ScrollView>
659
+ </react_native_1.View>
660
+
571
661
  {/* Quick Filter Horizontal Chips Bar with Live Counts */}
572
662
  <react_native_1.View style={{ marginBottom: 8 }}>
573
663
  <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{
@@ -853,7 +943,16 @@ const NetworkTab = react_1.default.memo(() => {
853
943
  ? `${logs.length} requests`
854
944
  : `${filteredLogs.length} of ${logs.length} filtered requests`}
855
945
  </react_native_1.Text>)}
856
- </react_native_1.View>} ListEmptyComponent={<EmptyState_1.default isSearch={search.length > 0 || statusFilters.size > 0}/>} ListFooterComponent={groupedData.length > 0 ? (<EndOfListFooter_1.default count={filteredLogs.length} label="requests"/>) : null} contentContainerStyle={[
946
+ </react_native_1.View>} ListEmptyComponent={<EmptyState_1.default isSearch={search.length > 0 ||
947
+ statusFilters.size > 0 ||
948
+ methodFilters.size > 0} searchQuery={search} customTitle={search.length > 0
949
+ ? 'No matching API requests'
950
+ : 'No network activity'} onClearSearch={() => {
951
+ setSearch('');
952
+ setStatusFilters(new Set());
953
+ setMethodFilters(new Set());
954
+ setSearchScope('all');
955
+ }}/>} ListFooterComponent={groupedData.length > 0 ? (<EndOfListFooter_1.default count={filteredLogs.length} label="requests"/>) : null} contentContainerStyle={[
857
956
  styles_1.default.listContent,
858
957
  filteredLogs.length === 0 && { flexGrow: 1 },
859
958
  ]} keyboardShouldPersistTaps="handled"/>
@@ -434,9 +434,25 @@ const ReduxTab = react_1.default.memo(() => {
434
434
  <react_native_1.View style={styles_1.default.searchContainer}>
435
435
  <NetworkIcons_1.SearchIcon color={AppColors_1.AppColors.grayTextWeak} size={15}/>
436
436
  <react_native_1.TextInput accessible={true} accessibilityRole="search" accessibilityLabel="Search Redux slices or actions" accessibilityHint="Type to filter state slices in real time" placeholder="Search Redux slices or actions..." placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={reduxSearch} onChangeText={setReduxSearch} style={styles_1.default.searchInput} autoCorrect={false} autoCapitalize="none"/>
437
- {reduxSearch.length > 0 && (<react_native_1.Pressable accessible={true} accessibilityRole="button" accessibilityLabel="Clear search input" onPress={() => setReduxSearch('')} hitSlop={10}>
438
- <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
439
- </react_native_1.Pressable>)}
437
+ {reduxSearch.length > 0 && (<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
438
+ <react_native_1.View style={{
439
+ backgroundColor: `${AppColors_1.AppColors.purple}20`,
440
+ borderRadius: 10,
441
+ paddingHorizontal: 6,
442
+ paddingVertical: 1.5,
443
+ }}>
444
+ <react_native_1.Text style={{
445
+ color: AppColors_1.AppColors.purple,
446
+ fontSize: 9.5,
447
+ fontFamily: AppFonts_1.AppFonts.interBold,
448
+ }}>
449
+ {filteredSlices.length}
450
+ </react_native_1.Text>
451
+ </react_native_1.View>
452
+ <react_native_1.Pressable accessible={true} accessibilityRole="button" accessibilityLabel="Clear search input" onPress={() => setReduxSearch('')} hitSlop={10}>
453
+ <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
454
+ </react_native_1.Pressable>
455
+ </react_native_1.View>)}
440
456
  </react_native_1.View>
441
457
 
442
458
  {/* Pause / Resume Live Updates Button */}
@@ -146,8 +146,8 @@ const SettingsPanel = () => {
146
146
  bundle: Boolean(tabVisibility?.bundle),
147
147
  performance: Boolean(tabVisibility?.performance),
148
148
  crash: Boolean(tabVisibility?.crash),
149
- device: Boolean(tabVisibility?.device ?? true),
150
- storage: Boolean(tabVisibility?.storage ?? true),
149
+ device: Boolean(tabVisibility?.device),
150
+ storage: Boolean(tabVisibility?.storage),
151
151
  }));
152
152
  // Synchronize staged state with tabVisibility when tabVisibility updates
153
153
  (0, react_1.useEffect)(() => {
@@ -159,8 +159,8 @@ const SettingsPanel = () => {
159
159
  bundle: Boolean(tabVisibility?.bundle),
160
160
  performance: Boolean(tabVisibility?.performance),
161
161
  crash: Boolean(tabVisibility?.crash),
162
- device: Boolean(tabVisibility?.device ?? true),
163
- storage: Boolean(tabVisibility?.storage ?? true),
162
+ device: Boolean(tabVisibility?.device),
163
+ storage: Boolean(tabVisibility?.storage),
164
164
  });
165
165
  }, [tabVisibility]);
166
166
  const hasUnsavedChanges = (0, react_1.useMemo)(() => {