react-native-inapp-inspector 1.1.25 → 1.1.26
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.
- package/android/build.gradle +36 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +114 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.java +28 -0
- package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
- package/dist/commonjs/components/ErrorBoundary.js +9 -145
- package/dist/commonjs/components/Inspector/CrashDetail.d.ts +3 -0
- package/dist/commonjs/components/Inspector/CrashDetail.js +796 -0
- package/dist/commonjs/components/Inspector/CrashFilterModal.d.ts +20 -0
- package/dist/commonjs/components/Inspector/CrashFilterModal.js +597 -0
- package/dist/commonjs/components/Inspector/CrashTab.d.ts +3 -0
- package/dist/commonjs/components/Inspector/CrashTab.js +727 -0
- package/dist/commonjs/components/Inspector/InspectorHeader.js +52 -23
- package/dist/commonjs/components/Inspector/LogDetail.js +4 -3
- package/dist/commonjs/components/Inspector/MainScreen.js +12 -3
- package/dist/commonjs/components/Inspector/SettingsPanel.js +90 -1
- package/dist/commonjs/components/Inspector/TabBar.js +15 -3
- package/dist/commonjs/components/NetworkIcons.d.ts +11 -0
- package/dist/commonjs/components/NetworkIcons.js +96 -1
- package/dist/commonjs/components/SegmentedTabs.js +2 -1
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.js +70 -44
- package/dist/commonjs/customHooks/consoleLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/consoleLogger.js +70 -6
- package/dist/commonjs/customHooks/crashHandler.d.ts +64 -0
- package/dist/commonjs/customHooks/crashHandler.js +681 -0
- package/dist/commonjs/customHooks/networkLogger.js +64 -48
- package/dist/commonjs/helpers/gaAnalyticsRegistry.js +1 -1
- package/dist/commonjs/i18n/locales/en.json +131 -0
- package/dist/commonjs/index.d.ts +3 -1
- package/dist/commonjs/index.js +95 -1
- package/dist/commonjs/types/enums.d.ts +41 -0
- package/dist/commonjs/types/enums.js +37 -1
- package/dist/commonjs/types/interfaces.d.ts +51 -1
- package/dist/esm/components/ErrorBoundary.d.ts +1 -1
- package/dist/esm/components/ErrorBoundary.js +10 -113
- package/dist/esm/components/Inspector/CrashDetail.d.ts +3 -0
- package/dist/esm/components/Inspector/CrashDetail.js +758 -0
- package/dist/esm/components/Inspector/CrashFilterModal.d.ts +20 -0
- package/dist/esm/components/Inspector/CrashFilterModal.js +557 -0
- package/dist/esm/components/Inspector/CrashTab.d.ts +3 -0
- package/dist/esm/components/Inspector/CrashTab.js +689 -0
- package/dist/esm/components/Inspector/InspectorHeader.js +52 -23
- package/dist/esm/components/Inspector/LogDetail.js +4 -3
- package/dist/esm/components/Inspector/MainScreen.js +12 -3
- package/dist/esm/components/Inspector/SettingsPanel.js +91 -2
- package/dist/esm/components/Inspector/TabBar.js +16 -4
- package/dist/esm/components/NetworkIcons.d.ts +11 -0
- package/dist/esm/components/NetworkIcons.js +83 -0
- package/dist/esm/components/SegmentedTabs.js +2 -1
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.js +70 -44
- package/dist/esm/customHooks/consoleLogger.d.ts +1 -0
- package/dist/esm/customHooks/consoleLogger.js +68 -5
- package/dist/esm/customHooks/crashHandler.d.ts +64 -0
- package/dist/esm/customHooks/crashHandler.js +659 -0
- package/dist/esm/customHooks/networkLogger.js +64 -48
- package/dist/esm/helpers/gaAnalyticsRegistry.js +1 -1
- package/dist/esm/i18n/locales/en.json +131 -0
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +73 -1
- package/dist/esm/types/enums.d.ts +41 -0
- package/dist/esm/types/enums.js +36 -0
- package/dist/esm/types/interfaces.d.ts +51 -1
- package/ios/NetworkInspectorModule.h +6 -0
- package/ios/NetworkInspectorModule.m +125 -0
- package/package.json +5 -2
- package/react-native-inapp-inspector.podspec +18 -0
|
@@ -12,7 +12,7 @@ import { LIB_VERSION } from '../../constants';
|
|
|
12
12
|
import { getStatusColor, getAppName, getBundleIdentifier, formatTime, getSize } from '../../helpers';
|
|
13
13
|
import { WhiteBackNavigation, TrashIcon, SettingsIcon, CloseWhite, ChevronIcon, ClockIcon, AppleIcon, AndroidIcon, PackageBoxIcon, } from '../NetworkIcons';
|
|
14
14
|
const InspectorHeader = React.memo(() => {
|
|
15
|
-
const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, setSettingsPage, closeModal, detailTitle, activeTab, environment, } = useInspector();
|
|
15
|
+
const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, setSettingsPage, closeModal, detailTitle, activeTab, environment, selectedCrash, setSelectedCrash, } = useInspector();
|
|
16
16
|
const envConfig = useMemo(() => {
|
|
17
17
|
const rawEnv = (environment || (__DEV__ ? 'DEV' : 'PROD')).trim();
|
|
18
18
|
const clean = rawEnv.toUpperCase();
|
|
@@ -51,7 +51,8 @@ const InspectorHeader = React.memo(() => {
|
|
|
51
51
|
const isDetailView = (activeTab === 'apis' && selected != null) ||
|
|
52
52
|
(activeTab === 'analytics' && selectedEvent != null) ||
|
|
53
53
|
(activeTab === 'logs' && selectedLog != null) ||
|
|
54
|
-
(activeTab === 'redux' && (selectedReduxSlice != null || selectedReduxAction != null))
|
|
54
|
+
(activeTab === 'redux' && (selectedReduxSlice != null || selectedReduxAction != null)) ||
|
|
55
|
+
(activeTab === 'crash' && selectedCrash != null);
|
|
55
56
|
const isAnySelected = isDetailView;
|
|
56
57
|
const headerTopPadding = Platform.OS === 'ios' && modalHeightPercent >= 95 ? 44 : 0;
|
|
57
58
|
return (<LinearGradient colors={[AppColors.purple, AppColors.brandPurple]} style={styles.headerGradient}>
|
|
@@ -62,8 +63,9 @@ const InspectorHeader = React.memo(() => {
|
|
|
62
63
|
{
|
|
63
64
|
flexDirection: 'row',
|
|
64
65
|
alignItems: 'center',
|
|
65
|
-
gap:
|
|
66
|
-
flex: !isDetailView ?
|
|
66
|
+
gap: 12,
|
|
67
|
+
flex: !isDetailView ? 1 : 0,
|
|
68
|
+
minWidth: 0,
|
|
67
69
|
},
|
|
68
70
|
]}>
|
|
69
71
|
<TouchableScale onPress={() => {
|
|
@@ -73,6 +75,7 @@ const InspectorHeader = React.memo(() => {
|
|
|
73
75
|
setSelectedLog(null);
|
|
74
76
|
setSelectedReduxSlice(null);
|
|
75
77
|
setSelectedReduxAction(null);
|
|
78
|
+
setSelectedCrash(null);
|
|
76
79
|
});
|
|
77
80
|
}} hitSlop={15} style={[
|
|
78
81
|
{
|
|
@@ -486,18 +489,58 @@ const InspectorHeader = React.memo(() => {
|
|
|
486
489
|
{selectedReduxAction.timestamp || 'Dispatched'}
|
|
487
490
|
</Text>
|
|
488
491
|
</View>
|
|
492
|
+
</View>) : activeTab === 'crash' && selectedCrash != null ? (<View style={styles.headerDetailCenter}>
|
|
493
|
+
<View style={styles.headerDetailRow}>
|
|
494
|
+
<View style={[
|
|
495
|
+
styles.headerMethodBadge,
|
|
496
|
+
{
|
|
497
|
+
backgroundColor: selectedCrash.isFatal
|
|
498
|
+
? '#DC2626'
|
|
499
|
+
: '#D97706',
|
|
500
|
+
},
|
|
501
|
+
]}>
|
|
502
|
+
<Text style={styles.headerMethodText}>
|
|
503
|
+
{selectedCrash.isFatal ? 'FATAL' : selectedCrash.type.toUpperCase()}
|
|
504
|
+
</Text>
|
|
505
|
+
</View>
|
|
506
|
+
<Text style={styles.headerDetailTitle} numberOfLines={1} ellipsizeMode="middle">
|
|
507
|
+
{selectedCrash.name || selectedCrash.message}
|
|
508
|
+
</Text>
|
|
509
|
+
</View>
|
|
510
|
+
<View style={styles.headerDetailSubRow}>
|
|
511
|
+
<View style={[
|
|
512
|
+
styles.headerStatusDot,
|
|
513
|
+
{
|
|
514
|
+
backgroundColor: selectedCrash.isFatal
|
|
515
|
+
? '#DC2626'
|
|
516
|
+
: '#F59E0B',
|
|
517
|
+
},
|
|
518
|
+
]}/>
|
|
519
|
+
<Text style={styles.headerSubTitle}>
|
|
520
|
+
{selectedCrash.timeStr || new Date(selectedCrash.timestamp).toLocaleTimeString()}
|
|
521
|
+
</Text>
|
|
522
|
+
{selectedCrash.deviceInfo?.platform && (<>
|
|
523
|
+
<Text style={[styles.headerSubTitle, { opacity: 0.6 }]}>•</Text>
|
|
524
|
+
<Text style={styles.headerSubTitle}>
|
|
525
|
+
{selectedCrash.deviceInfo.platform.toUpperCase()}
|
|
526
|
+
</Text>
|
|
527
|
+
</>)}
|
|
528
|
+
</View>
|
|
489
529
|
</View>) : null}
|
|
490
530
|
</View>)}
|
|
491
531
|
|
|
492
532
|
<View style={[
|
|
493
533
|
styles.headerRight,
|
|
494
|
-
|
|
534
|
+
{
|
|
535
|
+
flexDirection: 'row',
|
|
536
|
+
alignItems: 'center',
|
|
537
|
+
justifyContent: 'flex-end',
|
|
495
538
|
flexShrink: 0,
|
|
496
|
-
|
|
539
|
+
gap: 8,
|
|
497
540
|
},
|
|
498
541
|
]}>
|
|
499
542
|
{!isAnySelected && (<TouchableScale onPress={() => {
|
|
500
|
-
Alert.alert('Clear Everything', 'This clears all tabs — APIs, Logs, Analytics and
|
|
543
|
+
Alert.alert('Clear Everything', 'This clears all tabs — APIs, Logs, Analytics, Redux timeline and Crash history. Continue?', [
|
|
501
544
|
{ text: 'Cancel', style: 'cancel' },
|
|
502
545
|
{
|
|
503
546
|
text: 'Clear All',
|
|
@@ -505,13 +548,7 @@ const InspectorHeader = React.memo(() => {
|
|
|
505
548
|
style: 'destructive',
|
|
506
549
|
},
|
|
507
550
|
]);
|
|
508
|
-
}} hitSlop={15} style={
|
|
509
|
-
styles.closeButtonSquare,
|
|
510
|
-
{
|
|
511
|
-
marginRight: 8,
|
|
512
|
-
backgroundColor: `${AppColors.white}26`,
|
|
513
|
-
},
|
|
514
|
-
]}>
|
|
551
|
+
}} hitSlop={15} style={styles.closeButtonSquare}>
|
|
515
552
|
<Animated.View style={{
|
|
516
553
|
transform: [
|
|
517
554
|
{
|
|
@@ -532,15 +569,7 @@ const InspectorHeader = React.memo(() => {
|
|
|
532
569
|
</Animated.View>
|
|
533
570
|
</TouchableScale>)}
|
|
534
571
|
|
|
535
|
-
{
|
|
536
|
-
selectedEvent == null &&
|
|
537
|
-
selectedLog == null && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={[
|
|
538
|
-
styles.closeButtonSquare,
|
|
539
|
-
{
|
|
540
|
-
marginRight: 8,
|
|
541
|
-
backgroundColor: `${AppColors.white}26`,
|
|
542
|
-
},
|
|
543
|
-
]}>
|
|
572
|
+
{!isAnySelected && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={styles.closeButtonSquare}>
|
|
544
573
|
<SettingsIcon color={AppColors.white} size={16}/>
|
|
545
574
|
</TouchableScale>)}
|
|
546
575
|
|
|
@@ -262,7 +262,8 @@ const LogDetail = React.memo(() => {
|
|
|
262
262
|
fontSize: 13,
|
|
263
263
|
color: AppColors.primaryBlack,
|
|
264
264
|
lineHeight: 18,
|
|
265
|
-
|
|
265
|
+
flexShrink: 1,
|
|
266
|
+
}}>
|
|
266
267
|
{originFrame?.functionName && originFrame.functionName !== '<anonymous>'
|
|
267
268
|
? `${originFrame.functionName}()`
|
|
268
269
|
: originFrame?.fileName || t('console.consoleLog')}
|
|
@@ -277,11 +278,11 @@ const LogDetail = React.memo(() => {
|
|
|
277
278
|
paddingVertical: 2,
|
|
278
279
|
},
|
|
279
280
|
]}>
|
|
280
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 3 }}>
|
|
281
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 3, flexWrap: 'wrap', flexShrink: 1 }}>
|
|
281
282
|
<DocIcon color={AppColors.brandPurple} size={10}/>
|
|
282
283
|
<Text style={[
|
|
283
284
|
styles.metaChipText,
|
|
284
|
-
{ color: AppColors.brandPurple, fontSize: 10, fontFamily: AppFonts.interBold },
|
|
285
|
+
{ color: AppColors.brandPurple, fontSize: 10, fontFamily: AppFonts.interBold, flexShrink: 1 },
|
|
285
286
|
]}>
|
|
286
287
|
{originFrame.fileName}
|
|
287
288
|
{originFrame.lineNumber ? `:${originFrame.lineNumber}` : ''}
|
|
@@ -15,12 +15,14 @@ import ReduxTab from './ReduxTab';
|
|
|
15
15
|
import ReduxDetail from './ReduxDetail';
|
|
16
16
|
import BundleTab from './BundleTab';
|
|
17
17
|
import PerformanceTab from './PerformanceTab';
|
|
18
|
+
import CrashTab from './CrashTab';
|
|
19
|
+
import CrashDetail from './CrashDetail';
|
|
18
20
|
import SettingsPanel from './SettingsPanel';
|
|
19
21
|
import styles from '../../styles';
|
|
20
22
|
import { AppColors } from '../../styles/AppColors';
|
|
21
23
|
import NavigationTracker from './NavigationTracker';
|
|
22
24
|
const MainScreen = () => {
|
|
23
|
-
const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, settingsPage, activeTab, isReady, isEnabled, hasNavigationContext, setNavState, } = useInspector();
|
|
25
|
+
const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, selectedCrash, settingsPage, activeTab, isReady, isEnabled, hasNavigationContext, setNavState, } = useInspector();
|
|
24
26
|
// Lazy-mount each tab on first visit and cache it in memory for 0ms instantaneous switching
|
|
25
27
|
const [mountedTabs, setMountedTabs] = useState({
|
|
26
28
|
[activeTab]: true,
|
|
@@ -35,7 +37,8 @@ const MainScreen = () => {
|
|
|
35
37
|
const isDetailActive = (activeTab === 'apis' && selected != null) ||
|
|
36
38
|
(activeTab === 'analytics' && selectedEvent != null) ||
|
|
37
39
|
(activeTab === 'logs' && selectedLog != null) ||
|
|
38
|
-
(activeTab === 'redux' && (selectedReduxSlice != null || selectedReduxAction != null))
|
|
40
|
+
(activeTab === 'redux' && (selectedReduxSlice != null || selectedReduxAction != null)) ||
|
|
41
|
+
(activeTab === 'crash' && selectedCrash != null);
|
|
39
42
|
return (<>
|
|
40
43
|
{(Platform.OS === 'ios' || Platform.OS === 'android') && isEnabled && <FabLauncher />}
|
|
41
44
|
<Modal visible={visible} animationType={modalAnimationType} transparent>
|
|
@@ -53,7 +56,7 @@ const MainScreen = () => {
|
|
|
53
56
|
{/* ─── Horizontal Scrollable Tab Bar inside Content ─── */}
|
|
54
57
|
{!isDetailActive && settingsPage === null ? (<TabBar />) : null}
|
|
55
58
|
|
|
56
|
-
{isReady ? (isDetailActive ? (activeTab === 'apis' && selected != null ? (<NetworkDetail />) : activeTab === 'analytics' && selectedEvent != null ? (<AnalyticsDetail event={selectedEvent}/>) : activeTab === 'logs' && selectedLog != null ? (<LogDetail />) : activeTab === 'redux' ? (<ReduxDetail />) : null) : (<>
|
|
59
|
+
{isReady ? (isDetailActive ? (activeTab === 'apis' && selected != null ? (<NetworkDetail />) : activeTab === 'analytics' && selectedEvent != null ? (<AnalyticsDetail event={selectedEvent}/>) : activeTab === 'logs' && selectedLog != null ? (<LogDetail />) : activeTab === 'redux' ? (<ReduxDetail />) : activeTab === 'crash' && selectedCrash != null ? (<CrashDetail />) : null) : (<>
|
|
57
60
|
<View style={{
|
|
58
61
|
flex: 1,
|
|
59
62
|
display: activeTab === 'apis' ? 'flex' : 'none',
|
|
@@ -90,6 +93,12 @@ const MainScreen = () => {
|
|
|
90
93
|
}}>
|
|
91
94
|
{mountedTabs.performance && <PerformanceTab />}
|
|
92
95
|
</View>
|
|
96
|
+
<View style={{
|
|
97
|
+
flex: 1,
|
|
98
|
+
display: activeTab === 'crash' ? 'flex' : 'none',
|
|
99
|
+
}}>
|
|
100
|
+
{mountedTabs.crash && <CrashTab />}
|
|
101
|
+
</View>
|
|
93
102
|
</>)) : (<View style={styles.empty}>
|
|
94
103
|
<ActivityIndicator size="large" color={AppColors.purple}/>
|
|
95
104
|
<Text style={[styles.emptySub, { marginTop: 12 }]}>
|
|
@@ -12,9 +12,10 @@ import { isPersistentStorageAvailable } from '../../helpers/settingsStore';
|
|
|
12
12
|
import { clearNetworkLogs } from '../../customHooks/networkLogger';
|
|
13
13
|
import { clearConsoleLogs } from '../../customHooks/consoleLogger';
|
|
14
14
|
import { clearAnalyticsEvents } from '../../customHooks/analyticsLogger';
|
|
15
|
-
import {
|
|
15
|
+
import { clearCrashRecords, } from '../../customHooks/crashHandler';
|
|
16
|
+
import { SignalIcon, TerminalIcon, AnalyticsIcon, SettingsIcon, SunIcon, MoonIcon, ScreenIcon, MotionIcon, LayersIcon, EyeIcon, CheckIcon, TrashIcon, WhiteBackNavigation, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, ShieldAlertIcon, } from '../NetworkIcons';
|
|
16
17
|
const SettingsPanel = () => {
|
|
17
|
-
const { settingsPage, setSettingsPage, settingsActiveSubTab, setSettingsActiveSubTab, tabVisibility, toggleTabVisibility, defaultTab, setDefaultTab, isDark, setIsDark, modalHeightPercent, setModalHeightPercent, modalAnimationType, setModalAnimationType, showDuplicateLogs, setShowDuplicateLogs, showConsoleLevels, setShowConsoleLevels, resetToDefaults, storage, logs, consoleLogs, analyticsEvents, reduxState, maxNetworkLogs, setMaxNetworkLogs, maxConsoleLogs, setMaxConsoleLogs, reduxAutoRefresh, setReduxAutoRefreshState, reduxExpandDepth, setReduxExpandDepth, switchActiveTab, setSelected, setSelectedEvent, setReduxState, } = useInspector();
|
|
18
|
+
const { settingsPage, setSettingsPage, settingsActiveSubTab, setSettingsActiveSubTab, tabVisibility, toggleTabVisibility, defaultTab, setDefaultTab, isDark, setIsDark, modalHeightPercent, setModalHeightPercent, modalAnimationType, setModalAnimationType, showDuplicateLogs, setShowDuplicateLogs, showConsoleLevels, setShowConsoleLevels, resetToDefaults, storage, logs, consoleLogs, analyticsEvents, reduxState, maxNetworkLogs, setMaxNetworkLogs, maxConsoleLogs, setMaxConsoleLogs, reduxAutoRefresh, setReduxAutoRefreshState, reduxExpandDepth, setReduxExpandDepth, switchActiveTab, setSelected, setSelectedEvent, setReduxState, crashRecords, maxCrashLogs, setMaxCrashLogs, } = useInspector();
|
|
18
19
|
const isPersistent = isPersistentStorageAvailable();
|
|
19
20
|
const headerTopPadding = Platform.OS === 'ios' && modalHeightPercent >= 95 ? 44 : 0;
|
|
20
21
|
if (settingsPage === 'main') {
|
|
@@ -25,6 +26,7 @@ const SettingsPanel = () => {
|
|
|
25
26
|
{ key: 'redux', label: 'Redux', icon: 'redux' },
|
|
26
27
|
{ key: 'bundle', label: 'Bundle', icon: 'bundle' },
|
|
27
28
|
{ key: 'performance', label: 'Performance', icon: 'performance' },
|
|
29
|
+
{ key: 'crash', label: 'Crash', icon: 'crash' },
|
|
28
30
|
];
|
|
29
31
|
return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
|
|
30
32
|
{/* Settings Header with back button */}
|
|
@@ -235,6 +237,9 @@ const SettingsPanel = () => {
|
|
|
235
237
|
{tab.icon === 'performance' && (<PerformanceIcon color={isLocked
|
|
236
238
|
? AppColors.grayTextWeak
|
|
237
239
|
: AppColors.purple} size={11}/>)}
|
|
240
|
+
{tab.icon === 'crash' && (<CrashIcon color={isLocked
|
|
241
|
+
? AppColors.grayTextWeak
|
|
242
|
+
: AppColors.purple} size={11}/>)}
|
|
238
243
|
</View>
|
|
239
244
|
{/* Label + Required badge */}
|
|
240
245
|
<Text style={{
|
|
@@ -674,6 +679,7 @@ const SettingsPanel = () => {
|
|
|
674
679
|
{tab.icon === 'redux' && (<ReduxIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
|
|
675
680
|
{tab.icon === 'bundle' && (<PackageIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
|
|
676
681
|
{tab.icon === 'performance' && (<PerformanceIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
|
|
682
|
+
{tab.icon === 'crash' && (<CrashIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
|
|
677
683
|
</View>
|
|
678
684
|
<Text style={{
|
|
679
685
|
fontFamily: AppFonts.interBold,
|
|
@@ -1392,6 +1398,89 @@ const SettingsPanel = () => {
|
|
|
1392
1398
|
</View>
|
|
1393
1399
|
</ScrollView>);
|
|
1394
1400
|
}
|
|
1401
|
+
else if (settingsPage === 'crash') {
|
|
1402
|
+
title = 'Crash Settings';
|
|
1403
|
+
icon = <CrashIcon color={AppColors.white} size={16}/>;
|
|
1404
|
+
rightInfo = `Total: ${crashRecords?.length || 0}`;
|
|
1405
|
+
content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
|
|
1406
|
+
<View style={{
|
|
1407
|
+
backgroundColor: AppColors.primaryLight,
|
|
1408
|
+
padding: 16,
|
|
1409
|
+
borderRadius: 12,
|
|
1410
|
+
borderWidth: 1,
|
|
1411
|
+
borderColor: AppColors.grayBorderSecondary,
|
|
1412
|
+
gap: 4,
|
|
1413
|
+
}}>
|
|
1414
|
+
{renderSettingRow({
|
|
1415
|
+
icon: <LayersIcon color={AppColors.purple} size={16}/>,
|
|
1416
|
+
label: 'Max Crash Logs',
|
|
1417
|
+
description: 'How many crash records to preserve in history',
|
|
1418
|
+
picker: {
|
|
1419
|
+
options: [25, 50, 100, 200],
|
|
1420
|
+
selectedValue: maxCrashLogs || 100,
|
|
1421
|
+
onSelect: val => setMaxCrashLogs(val),
|
|
1422
|
+
},
|
|
1423
|
+
})}
|
|
1424
|
+
<View style={{ height: 1, backgroundColor: AppColors.dividerColor }}/>
|
|
1425
|
+
{renderSettingRow({
|
|
1426
|
+
icon: <ShieldAlertIcon color={AppColors.greenColor} size={16}/>,
|
|
1427
|
+
label: 'Global Crash Guard',
|
|
1428
|
+
description: 'Intercepts native, JS, and render errors directly',
|
|
1429
|
+
isLast: true,
|
|
1430
|
+
right: (<View style={{
|
|
1431
|
+
paddingHorizontal: 8,
|
|
1432
|
+
paddingVertical: 4,
|
|
1433
|
+
borderRadius: 6,
|
|
1434
|
+
backgroundColor: `${AppColors.greenColor}1F`,
|
|
1435
|
+
}}>
|
|
1436
|
+
<Text style={{
|
|
1437
|
+
fontFamily: AppFonts.interBold,
|
|
1438
|
+
fontSize: 10,
|
|
1439
|
+
color: AppColors.greenColor,
|
|
1440
|
+
}}>
|
|
1441
|
+
PROTECTED
|
|
1442
|
+
</Text>
|
|
1443
|
+
</View>),
|
|
1444
|
+
})}
|
|
1445
|
+
</View>
|
|
1446
|
+
|
|
1447
|
+
<View style={{
|
|
1448
|
+
backgroundColor: AppColors.primaryLight,
|
|
1449
|
+
borderRadius: 12,
|
|
1450
|
+
borderWidth: 1,
|
|
1451
|
+
borderColor: AppColors.grayBorderSecondary,
|
|
1452
|
+
padding: 16,
|
|
1453
|
+
marginTop: 12,
|
|
1454
|
+
}}>
|
|
1455
|
+
{renderSettingRow({
|
|
1456
|
+
icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
|
|
1457
|
+
label: 'Clear Crash History',
|
|
1458
|
+
description: `${crashRecords?.length || 0} crash logs stored`,
|
|
1459
|
+
isLast: true,
|
|
1460
|
+
onPress: () => {
|
|
1461
|
+
clearCrashRecords();
|
|
1462
|
+
Alert.alert('Success', 'Crash logs cleared.');
|
|
1463
|
+
},
|
|
1464
|
+
right: (<View style={{
|
|
1465
|
+
paddingHorizontal: 10,
|
|
1466
|
+
paddingVertical: 5,
|
|
1467
|
+
borderRadius: 7,
|
|
1468
|
+
backgroundColor: `${AppColors.errorColor}14`,
|
|
1469
|
+
borderWidth: 1,
|
|
1470
|
+
borderColor: `${AppColors.errorColor}33`,
|
|
1471
|
+
}}>
|
|
1472
|
+
<Text style={{
|
|
1473
|
+
fontFamily: AppFonts.interBold,
|
|
1474
|
+
fontSize: 11,
|
|
1475
|
+
color: AppColors.errorColor,
|
|
1476
|
+
}}>
|
|
1477
|
+
Clear
|
|
1478
|
+
</Text>
|
|
1479
|
+
</View>),
|
|
1480
|
+
})}
|
|
1481
|
+
</View>
|
|
1482
|
+
</ScrollView>);
|
|
1483
|
+
}
|
|
1395
1484
|
return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
|
|
1396
1485
|
<LinearGradient colors={[AppColors.purple, AppColors.brandPurple]} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.headerGradient}>
|
|
1397
1486
|
<View style={{ paddingTop: headerTopPadding, width: '100%' }}>
|
|
@@ -4,9 +4,9 @@ import { useInspector } from './InspectorContext';
|
|
|
4
4
|
import TouchableScale from '../TouchableScale';
|
|
5
5
|
import styles from '../../styles';
|
|
6
6
|
import { AppColors } from '../../styles/AppColors';
|
|
7
|
-
import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, } from '../NetworkIcons';
|
|
7
|
+
import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, } from '../NetworkIcons';
|
|
8
8
|
const TabBar = React.memo(() => {
|
|
9
|
-
const { activeTab, switchActiveTab, tabVisibility, logs, consoleLogs, analyticsEvents, lastReadApisCount, lastReadLogsCount, unreadPulseAnim, } = useInspector();
|
|
9
|
+
const { activeTab, switchActiveTab, tabVisibility, logs, consoleLogs, analyticsEvents, crashRecords, lastReadApisCount, lastReadLogsCount, lastReadCrashesCount, unreadPulseAnim, } = useInspector();
|
|
10
10
|
return (<View style={styles.tabBarContainer}>
|
|
11
11
|
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ paddingRight: 16 }}>
|
|
12
12
|
{[
|
|
@@ -46,18 +46,28 @@ const TabBar = React.memo(() => {
|
|
|
46
46
|
count: 0,
|
|
47
47
|
icon: 'performance',
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
key: 'crash',
|
|
51
|
+
label: 'Crash',
|
|
52
|
+
count: crashRecords?.length || 0,
|
|
53
|
+
icon: 'crash',
|
|
54
|
+
},
|
|
49
55
|
]
|
|
50
56
|
.filter(tab => tabVisibility?.[tab.key])
|
|
51
57
|
.map(tab => {
|
|
52
58
|
const isActive = activeTab === tab.key;
|
|
53
59
|
const iconColor = isActive
|
|
54
60
|
? AppColors.white
|
|
55
|
-
:
|
|
61
|
+
: tab.key === 'crash' && tab.count > 0
|
|
62
|
+
? AppColors.errorColor
|
|
63
|
+
: AppColors.grayText;
|
|
56
64
|
const countLabel = tab.count > 9 ? '9+' : String(tab.count);
|
|
57
65
|
const hasUnreadApis = activeTab !== 'apis' &&
|
|
58
66
|
logs.length > lastReadApisCount;
|
|
59
67
|
const hasUnreadLogs = activeTab !== 'logs' &&
|
|
60
68
|
consoleLogs.length > lastReadLogsCount;
|
|
69
|
+
const hasUnreadCrashes = activeTab !== 'crash' &&
|
|
70
|
+
(crashRecords?.length || 0) > (lastReadCrashesCount || 0);
|
|
61
71
|
return (<TouchableScale key={tab.key} onPress={() => switchActiveTab(tab.key)} style={[
|
|
62
72
|
styles.contentTabButton,
|
|
63
73
|
isActive && styles.contentTabButtonActive,
|
|
@@ -73,6 +83,7 @@ const TabBar = React.memo(() => {
|
|
|
73
83
|
{tab.icon === 'redux' && (<ReduxIcon color={iconColor} size={14}/>)}
|
|
74
84
|
{tab.icon === 'bundle' && (<PackageIcon color={iconColor} size={14}/>)}
|
|
75
85
|
{tab.icon === 'performance' && (<PerformanceIcon color={iconColor} size={14}/>)}
|
|
86
|
+
{tab.icon === 'crash' && (<CrashIcon color={iconColor} size={14}/>)}
|
|
76
87
|
<Text numberOfLines={1} ellipsizeMode="tail" style={[
|
|
77
88
|
styles.contentTabButtonText,
|
|
78
89
|
isActive &&
|
|
@@ -82,7 +93,8 @@ const TabBar = React.memo(() => {
|
|
|
82
93
|
{tab.count > 0 ? `(${countLabel})` : ''}
|
|
83
94
|
</Text>
|
|
84
95
|
{((tab.key === 'apis' && hasUnreadApis) ||
|
|
85
|
-
(tab.key === 'logs' && hasUnreadLogs)
|
|
96
|
+
(tab.key === 'logs' && hasUnreadLogs) ||
|
|
97
|
+
(tab.key === 'crash' && hasUnreadCrashes)) && (<Animated.View style={{
|
|
86
98
|
width: 6,
|
|
87
99
|
height: 6,
|
|
88
100
|
borderRadius: 3,
|
|
@@ -92,3 +92,14 @@ export declare const PinIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
|
92
92
|
export declare const RepeatIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
93
93
|
export declare const TargetGoalIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
94
94
|
export declare const UserCheckIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
95
|
+
export declare const CrashIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
96
|
+
export declare const ShieldAlertIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
97
|
+
export declare const SkullIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
98
|
+
export declare const ChipIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
99
|
+
export declare const LayoutIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
100
|
+
export declare const StackTraceIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
101
|
+
export declare const DiagnosticsIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
102
|
+
export declare const TrailIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
103
|
+
export declare const RawJsonIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
104
|
+
export declare const AppFramesIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
105
|
+
export declare const AllFramesIcon: ({ color, size, }: any) => React.JSX.Element;
|
|
@@ -559,3 +559,86 @@ export const UserCheckIcon = ({ color = AppColors.grayTextWeak, size = 14, }) =>
|
|
|
559
559
|
<Path d="M16 11l2 2 4-4" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
|
|
560
560
|
</Svg>);
|
|
561
561
|
};
|
|
562
|
+
export const CrashIcon = ({ color = AppColors.errorColor, size = 14, }) => {
|
|
563
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
564
|
+
{/* Bug / Crash Hybrid Icon */}
|
|
565
|
+
<Path d="M12 2v3M4.93 4.93l2.12 2.12M19.07 4.93l-2.12 2.12M9 10h6M8 14h8M9 18h6" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
|
|
566
|
+
<Path d="M12 8a6 6 0 0 1 6 6v3a6 6 0 0 1-12 0v-3a6 6 0 0 1 6-6z" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
|
|
567
|
+
<Path d="M3 13h3M18 13h3M4 19l2.5-1.5M20 19l-2.5-1.5M4 9l2.5 1.5M20 9l-2.5 1.5" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
|
|
568
|
+
</Svg>);
|
|
569
|
+
};
|
|
570
|
+
export const ShieldAlertIcon = ({ color = AppColors.errorColor, size = 14, }) => {
|
|
571
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
572
|
+
<Path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
|
|
573
|
+
<Line x1="12" y1="8" x2="12" y2="12" stroke={color} strokeWidth="2" strokeLinecap="round"/>
|
|
574
|
+
<Circle cx="12" cy="16" r="1" fill={color}/>
|
|
575
|
+
</Svg>);
|
|
576
|
+
};
|
|
577
|
+
export const SkullIcon = ({ color = AppColors.errorColor, size = 14, }) => {
|
|
578
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
579
|
+
<Circle cx="12" cy="12" r="9" stroke={color} strokeWidth="1.8"/>
|
|
580
|
+
<Circle cx="9" cy="11" r="1.6" fill={color}/>
|
|
581
|
+
<Circle cx="15" cy="11" r="1.6" fill={color}/>
|
|
582
|
+
<Path d="M8 16c1.2 1 3.2 1.2 4 1.2.8 0 2.8-.2 4-1.2" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
|
|
583
|
+
<Line x1="12" y1="16" x2="12" y2="18" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
|
|
584
|
+
</Svg>);
|
|
585
|
+
};
|
|
586
|
+
export const ChipIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
|
|
587
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
588
|
+
<Rect x="7" y="7" width="10" height="10" rx="2" stroke={color} strokeWidth="1.8"/>
|
|
589
|
+
<Rect x="10" y="10" width="4" height="4" fill={color}/>
|
|
590
|
+
<Line x1="9" y1="3" x2="9" y2="7" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
591
|
+
<Line x1="15" y1="3" x2="15" y2="7" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
592
|
+
<Line x1="9" y1="17" x2="9" y2="21" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
593
|
+
<Line x1="15" y1="17" x2="15" y2="21" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
594
|
+
<Line x1="3" y1="9" x2="7" y2="9" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
595
|
+
<Line x1="3" y1="15" x2="7" y2="15" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
596
|
+
<Line x1="17" y1="9" x2="21" y2="9" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
597
|
+
<Line x1="17" y1="15" x2="21" y2="15" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
598
|
+
</Svg>);
|
|
599
|
+
};
|
|
600
|
+
export const LayoutIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
|
|
601
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
602
|
+
<Rect x="3" y="3" width="18" height="18" rx="2" stroke={color} strokeWidth="1.8"/>
|
|
603
|
+
<Line x1="3" y1="9" x2="21" y2="9" stroke={color} strokeWidth="1.8"/>
|
|
604
|
+
<Line x1="9" y1="9" x2="9" y2="21" stroke={color} strokeWidth="1.8"/>
|
|
605
|
+
<Rect x="12" y="12" width="6" height="6" fill={color}/>
|
|
606
|
+
</Svg>);
|
|
607
|
+
};
|
|
608
|
+
export const StackTraceIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
|
|
609
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
610
|
+
<Path d="M4 6h16M4 10h11M4 14h16M4 18h9" stroke={color} strokeWidth="2" strokeLinecap="round"/>
|
|
611
|
+
<Path d="M7.5 12.5 4 14l3.5 1.5" stroke={color} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/>
|
|
612
|
+
</Svg>);
|
|
613
|
+
};
|
|
614
|
+
export const DiagnosticsIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
|
|
615
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
616
|
+
<Path d="M3 12h3l2-5 3 9 2-6 1.5 2H21" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
|
617
|
+
<Line x1="4" y1="19" x2="20" y2="19" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
618
|
+
</Svg>);
|
|
619
|
+
};
|
|
620
|
+
export const TrailIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
|
|
621
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
622
|
+
<Circle cx="5" cy="18" r="2" fill={color}/>
|
|
623
|
+
<Circle cx="12" cy="12" r="2" fill={color}/>
|
|
624
|
+
<Circle cx="19" cy="6" r="2" fill={color}/>
|
|
625
|
+
<Path d="M6.5 16.5 10.5 13.5M13.5 10.5 17.5 7.5" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
|
|
626
|
+
</Svg>);
|
|
627
|
+
};
|
|
628
|
+
export const RawJsonIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
|
|
629
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
630
|
+
<Path d="M8 3c-2 1-3 2.5-3 5 0 2-1 3.5-2 4 1 .5 2 2 2 4 0 2.5 1 4 3 5M16 3c2 1 3 2.5 3 5 0 2 1 3.5 2 4-1 .5-2 2-2 4 0 2.5-1 4-3 5" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
|
|
631
|
+
</Svg>);
|
|
632
|
+
};
|
|
633
|
+
export const AppFramesIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
|
|
634
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
635
|
+
<Path d="M4 6h16M4 10h11M4 14h16M4 18h9" stroke={color} strokeWidth="2" strokeLinecap="round"/>
|
|
636
|
+
<Path d="M18 12.5l2 2 3-3.5" stroke="#059669" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
|
|
637
|
+
</Svg>);
|
|
638
|
+
};
|
|
639
|
+
export const AllFramesIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
|
|
640
|
+
return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
641
|
+
<Path d="M4 4h16M4 8h16M4 12h16M4 16h16M4 20h10" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
|
|
642
|
+
<Rect x="16" y="16" width="4" height="4" rx="1" fill={color}/>
|
|
643
|
+
</Svg>);
|
|
644
|
+
};
|
|
@@ -40,7 +40,8 @@ const SegmentedTabs = React.memo(({ tabs, activeKey, onChange, style }) => (<Vie
|
|
|
40
40
|
},
|
|
41
41
|
]}>
|
|
42
42
|
{tab.icon ? tab.icon(isActive) : null}
|
|
43
|
-
<Text style={{
|
|
43
|
+
<Text numberOfLines={1} ellipsizeMode="tail" style={{
|
|
44
|
+
flexShrink: 1,
|
|
44
45
|
fontFamily: AppFonts.interBold,
|
|
45
46
|
fontSize: 10.5,
|
|
46
47
|
color: isActive
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "1.1.
|
|
1
|
+
export declare const LIB_VERSION = "1.1.26";
|