react-native-inapp-inspector 1.1.24 → 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/AnalyticsEventCard.js +94 -88
- package/dist/commonjs/components/ConsoleLogCard.js +49 -25
- package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
- package/dist/commonjs/components/ErrorBoundary.js +9 -145
- package/dist/commonjs/components/Inspector/AnalyticsFilterModal.d.ts +7 -0
- package/dist/commonjs/components/Inspector/AnalyticsFilterModal.js +1002 -0
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +637 -10
- package/dist/commonjs/components/Inspector/BundleTab.d.ts +1 -1
- package/dist/commonjs/components/Inspector/BundleTab.js +826 -406
- 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/InspectorContext.js +6 -1
- package/dist/commonjs/components/Inspector/InspectorHeader.js +65 -28
- package/dist/commonjs/components/Inspector/LogDetail.js +227 -114
- package/dist/commonjs/components/Inspector/MainScreen.js +13 -4
- package/dist/commonjs/components/Inspector/NetworkDetail.js +131 -81
- package/dist/commonjs/components/Inspector/PerformanceTab.js +20 -10
- 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 +25 -0
- package/dist/commonjs/components/NetworkIcons.js +188 -1
- package/dist/commonjs/components/SegmentedTabs.js +33 -23
- package/dist/commonjs/components/TreeNode.js +13 -12
- 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/bundleAnalyzer.d.ts +5 -1
- package/dist/commonjs/customHooks/bundleAnalyzer.js +497 -126
- package/dist/commonjs/customHooks/consoleLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/consoleLogger.js +153 -51
- package/dist/commonjs/customHooks/crashHandler.d.ts +64 -0
- package/dist/commonjs/customHooks/crashHandler.js +681 -0
- package/dist/commonjs/customHooks/networkLogger.js +74 -49
- package/dist/commonjs/customHooks/performanceTracker.d.ts +8 -0
- package/dist/commonjs/customHooks/performanceTracker.js +44 -3
- package/dist/commonjs/decorators/index.d.ts +49 -0
- package/dist/commonjs/decorators/index.js +142 -0
- package/dist/commonjs/helpers/gaAnalyticsRegistry.d.ts +18 -0
- package/dist/commonjs/helpers/gaAnalyticsRegistry.js +174 -0
- package/dist/commonjs/helpers/index.d.ts +7 -4
- package/dist/commonjs/helpers/index.js +102 -64
- package/dist/commonjs/i18n/locales/en.json +182 -4
- package/dist/commonjs/index.d.ts +6 -0
- package/dist/commonjs/index.js +310 -8
- package/dist/commonjs/styles/index.d.ts +4 -1
- package/dist/commonjs/styles/index.js +22 -19
- package/dist/commonjs/types/enums.d.ts +156 -9
- package/dist/commonjs/types/enums.js +139 -2
- package/dist/commonjs/types/interfaces.d.ts +70 -1
- package/dist/esm/components/AnalyticsEventCard.js +95 -89
- package/dist/esm/components/ConsoleLogCard.js +49 -25
- package/dist/esm/components/ErrorBoundary.d.ts +1 -1
- package/dist/esm/components/ErrorBoundary.js +10 -113
- package/dist/esm/components/Inspector/AnalyticsFilterModal.d.ts +7 -0
- package/dist/esm/components/Inspector/AnalyticsFilterModal.js +964 -0
- package/dist/esm/components/Inspector/AnalyticsTab.js +639 -12
- package/dist/esm/components/Inspector/BundleTab.d.ts +1 -1
- package/dist/esm/components/Inspector/BundleTab.js +827 -407
- 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/InspectorContext.js +1 -0
- package/dist/esm/components/Inspector/InspectorHeader.js +66 -29
- package/dist/esm/components/Inspector/LogDetail.js +227 -114
- package/dist/esm/components/Inspector/MainScreen.js +14 -5
- package/dist/esm/components/Inspector/NetworkDetail.js +132 -49
- package/dist/esm/components/Inspector/PerformanceTab.js +20 -10
- 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 +25 -0
- package/dist/esm/components/NetworkIcons.js +161 -0
- package/dist/esm/components/SegmentedTabs.js +33 -23
- package/dist/esm/components/TreeNode.js +13 -12
- 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/bundleAnalyzer.d.ts +5 -1
- package/dist/esm/customHooks/bundleAnalyzer.js +493 -125
- package/dist/esm/customHooks/consoleLogger.d.ts +1 -0
- package/dist/esm/customHooks/consoleLogger.js +151 -50
- package/dist/esm/customHooks/crashHandler.d.ts +64 -0
- package/dist/esm/customHooks/crashHandler.js +659 -0
- package/dist/esm/customHooks/networkLogger.js +74 -49
- package/dist/esm/customHooks/performanceTracker.d.ts +8 -0
- package/dist/esm/customHooks/performanceTracker.js +38 -1
- package/dist/esm/decorators/index.d.ts +49 -0
- package/dist/esm/decorators/index.js +137 -0
- package/dist/esm/helpers/gaAnalyticsRegistry.d.ts +18 -0
- package/dist/esm/helpers/gaAnalyticsRegistry.js +169 -0
- package/dist/esm/helpers/index.d.ts +7 -4
- package/dist/esm/helpers/index.js +100 -63
- package/dist/esm/i18n/locales/en.json +182 -4
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.js +262 -8
- package/dist/esm/styles/index.d.ts +4 -1
- package/dist/esm/styles/index.js +22 -19
- package/dist/esm/types/enums.d.ts +156 -9
- package/dist/esm/types/enums.js +138 -3
- package/dist/esm/types/interfaces.d.ts +70 -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
|
@@ -10,9 +10,9 @@ import { AppFonts } from '../../styles/AppFonts';
|
|
|
10
10
|
import { METHOD_COLORS } from '../../constants';
|
|
11
11
|
import { LIB_VERSION } from '../../constants';
|
|
12
12
|
import { getStatusColor, getAppName, getBundleIdentifier, formatTime, getSize } from '../../helpers';
|
|
13
|
-
import { WhiteBackNavigation, TrashIcon, SettingsIcon, CloseWhite, ChevronIcon, ClockIcon, } from '../NetworkIcons';
|
|
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
|
{
|
|
@@ -194,10 +197,14 @@ const InspectorHeader = React.memo(() => {
|
|
|
194
197
|
borderColor: `${AppColors.white}2E`,
|
|
195
198
|
}}>
|
|
196
199
|
<View style={{
|
|
197
|
-
|
|
198
|
-
|
|
200
|
+
flexDirection: 'row',
|
|
201
|
+
alignItems: 'center',
|
|
202
|
+
gap: 3.5,
|
|
203
|
+
paddingHorizontal: 6,
|
|
204
|
+
paddingVertical: 2.5,
|
|
199
205
|
backgroundColor: `${AppColors.white}47`,
|
|
200
206
|
}}>
|
|
207
|
+
{Platform.OS === 'ios' ? (<AppleIcon color={AppColors.white} size={10}/>) : (<AndroidIcon color={AppColors.white} size={10}/>)}
|
|
201
208
|
<Text style={{
|
|
202
209
|
fontFamily: AppFonts.interBold,
|
|
203
210
|
fontSize: 9,
|
|
@@ -209,7 +216,7 @@ const InspectorHeader = React.memo(() => {
|
|
|
209
216
|
</View>
|
|
210
217
|
<View style={{
|
|
211
218
|
paddingHorizontal: 5,
|
|
212
|
-
paddingVertical: 2,
|
|
219
|
+
paddingVertical: 2.5,
|
|
213
220
|
backgroundColor: `${AppColors.white}1F`,
|
|
214
221
|
}}>
|
|
215
222
|
<Text style={{
|
|
@@ -230,10 +237,14 @@ const InspectorHeader = React.memo(() => {
|
|
|
230
237
|
borderColor: `${AppColors.white}2E`,
|
|
231
238
|
}}>
|
|
232
239
|
<View style={{
|
|
233
|
-
|
|
234
|
-
|
|
240
|
+
flexDirection: 'row',
|
|
241
|
+
alignItems: 'center',
|
|
242
|
+
gap: 3.5,
|
|
243
|
+
paddingHorizontal: 6,
|
|
244
|
+
paddingVertical: 2.5,
|
|
235
245
|
backgroundColor: `${AppColors.white}47`,
|
|
236
246
|
}}>
|
|
247
|
+
<PackageBoxIcon color={AppColors.white} size={10}/>
|
|
237
248
|
<Text style={{
|
|
238
249
|
fontFamily: AppFonts.interBold,
|
|
239
250
|
fontSize: 9,
|
|
@@ -478,18 +489,58 @@ const InspectorHeader = React.memo(() => {
|
|
|
478
489
|
{selectedReduxAction.timestamp || 'Dispatched'}
|
|
479
490
|
</Text>
|
|
480
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>
|
|
481
529
|
</View>) : null}
|
|
482
530
|
</View>)}
|
|
483
531
|
|
|
484
532
|
<View style={[
|
|
485
533
|
styles.headerRight,
|
|
486
|
-
|
|
534
|
+
{
|
|
535
|
+
flexDirection: 'row',
|
|
536
|
+
alignItems: 'center',
|
|
537
|
+
justifyContent: 'flex-end',
|
|
487
538
|
flexShrink: 0,
|
|
488
|
-
|
|
539
|
+
gap: 8,
|
|
489
540
|
},
|
|
490
541
|
]}>
|
|
491
542
|
{!isAnySelected && (<TouchableScale onPress={() => {
|
|
492
|
-
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?', [
|
|
493
544
|
{ text: 'Cancel', style: 'cancel' },
|
|
494
545
|
{
|
|
495
546
|
text: 'Clear All',
|
|
@@ -497,13 +548,7 @@ const InspectorHeader = React.memo(() => {
|
|
|
497
548
|
style: 'destructive',
|
|
498
549
|
},
|
|
499
550
|
]);
|
|
500
|
-
}} hitSlop={15} style={
|
|
501
|
-
styles.closeButtonSquare,
|
|
502
|
-
{
|
|
503
|
-
marginRight: 8,
|
|
504
|
-
backgroundColor: `${AppColors.white}26`,
|
|
505
|
-
},
|
|
506
|
-
]}>
|
|
551
|
+
}} hitSlop={15} style={styles.closeButtonSquare}>
|
|
507
552
|
<Animated.View style={{
|
|
508
553
|
transform: [
|
|
509
554
|
{
|
|
@@ -524,15 +569,7 @@ const InspectorHeader = React.memo(() => {
|
|
|
524
569
|
</Animated.View>
|
|
525
570
|
</TouchableScale>)}
|
|
526
571
|
|
|
527
|
-
{
|
|
528
|
-
selectedEvent == null &&
|
|
529
|
-
selectedLog == null && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={[
|
|
530
|
-
styles.closeButtonSquare,
|
|
531
|
-
{
|
|
532
|
-
marginRight: 8,
|
|
533
|
-
backgroundColor: `${AppColors.white}26`,
|
|
534
|
-
},
|
|
535
|
-
]}>
|
|
572
|
+
{!isAnySelected && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={styles.closeButtonSquare}>
|
|
536
573
|
<SettingsIcon color={AppColors.white} size={16}/>
|
|
537
574
|
</TouchableScale>)}
|
|
538
575
|
|
|
@@ -35,6 +35,7 @@ const LogDetail = React.memo(() => {
|
|
|
35
35
|
const jsonContent = useMemo(() => (selectedLog ? getJsonContent(selectedLog.message) : null), [selectedLog]);
|
|
36
36
|
const [stackViewMode, setStackViewMode] = useState('structured');
|
|
37
37
|
const [stackSource, setStackSource] = useState('caller');
|
|
38
|
+
const [stackFilter, setStackFilter] = useState('app');
|
|
38
39
|
const activeStackString = useMemo(() => {
|
|
39
40
|
if (!selectedLog)
|
|
40
41
|
return '';
|
|
@@ -43,21 +44,6 @@ const LogDetail = React.memo(() => {
|
|
|
43
44
|
}
|
|
44
45
|
return selectedLog.stack || selectedLog.caller || '';
|
|
45
46
|
}, [selectedLog, stackSource]);
|
|
46
|
-
const originFrame = useMemo(() => {
|
|
47
|
-
if (!selectedLog)
|
|
48
|
-
return null;
|
|
49
|
-
if (selectedLog.caller && selectedLog.caller !== 'Unknown') {
|
|
50
|
-
return parseStackLine(selectedLog.caller, true);
|
|
51
|
-
}
|
|
52
|
-
if (selectedLog.stack) {
|
|
53
|
-
const firstLine = selectedLog.stack
|
|
54
|
-
.split('\n')
|
|
55
|
-
.find(l => l.trim().length > 0);
|
|
56
|
-
if (firstLine)
|
|
57
|
-
return parseStackLine(firstLine, true);
|
|
58
|
-
}
|
|
59
|
-
return null;
|
|
60
|
-
}, [selectedLog]);
|
|
61
47
|
const parsedStackFrames = useMemo(() => {
|
|
62
48
|
if (!activeStackString)
|
|
63
49
|
return [];
|
|
@@ -67,6 +53,29 @@ const LogDetail = React.memo(() => {
|
|
|
67
53
|
.filter(l => l.length > 0)
|
|
68
54
|
.map((line, idx) => parseStackLine(line, idx === 0));
|
|
69
55
|
}, [activeStackString]);
|
|
56
|
+
const appStackFrames = useMemo(() => {
|
|
57
|
+
return parsedStackFrames.filter(f => f.frameType === 'app' || !f.isRuntimeNoise);
|
|
58
|
+
}, [parsedStackFrames]);
|
|
59
|
+
const displayedFrames = useMemo(() => {
|
|
60
|
+
if (stackFilter === 'app' && appStackFrames.length > 0) {
|
|
61
|
+
return appStackFrames;
|
|
62
|
+
}
|
|
63
|
+
return parsedStackFrames;
|
|
64
|
+
}, [stackFilter, appStackFrames, parsedStackFrames]);
|
|
65
|
+
const originFrame = useMemo(() => {
|
|
66
|
+
if (!selectedLog)
|
|
67
|
+
return null;
|
|
68
|
+
if (appStackFrames.length > 0) {
|
|
69
|
+
return appStackFrames[0];
|
|
70
|
+
}
|
|
71
|
+
if (selectedLog.caller && selectedLog.caller !== 'Unknown') {
|
|
72
|
+
return parseStackLine(selectedLog.caller, true);
|
|
73
|
+
}
|
|
74
|
+
if (parsedStackFrames.length > 0) {
|
|
75
|
+
return parsedStackFrames[0];
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}, [selectedLog, appStackFrames, parsedStackFrames]);
|
|
70
79
|
if (!selectedLog)
|
|
71
80
|
return null;
|
|
72
81
|
const isDark = AppColors.primaryLight !== AppColors.white;
|
|
@@ -100,14 +109,14 @@ const LogDetail = React.memo(() => {
|
|
|
100
109
|
const subTabs = [
|
|
101
110
|
{
|
|
102
111
|
key: 'output',
|
|
103
|
-
label: '
|
|
112
|
+
label: t('console.tabOutput'),
|
|
104
113
|
icon: (isActive) => (<TerminalIcon color={isActive ? AppColors.white : AppColors.grayTextWeak} size={12}/>),
|
|
105
114
|
},
|
|
106
115
|
...(hasMultipleArgs
|
|
107
116
|
? [
|
|
108
117
|
{
|
|
109
118
|
key: 'arguments',
|
|
110
|
-
label:
|
|
119
|
+
label: t('console.tabArgs', { count: selectedLog.rawArgs?.length }),
|
|
111
120
|
icon: (isActive) => (<RequestIcon color={isActive ? AppColors.white : AppColors.grayTextWeak} size={12}/>),
|
|
112
121
|
},
|
|
113
122
|
]
|
|
@@ -116,14 +125,14 @@ const LogDetail = React.memo(() => {
|
|
|
116
125
|
? [
|
|
117
126
|
{
|
|
118
127
|
key: 'stack',
|
|
119
|
-
label: '
|
|
128
|
+
label: t('console.tabStack'),
|
|
120
129
|
icon: (isActive) => (<LayersIcon color={isActive ? AppColors.white : AppColors.grayTextWeak} size={12}/>),
|
|
121
130
|
},
|
|
122
131
|
]
|
|
123
132
|
: []),
|
|
124
133
|
{
|
|
125
134
|
key: 'metadata',
|
|
126
|
-
label: '
|
|
135
|
+
label: t('console.tabMetadata'),
|
|
127
136
|
icon: (isActive) => (<InfoCircleIcon color={isActive ? AppColors.white : AppColors.grayTextWeak} size={12}/>),
|
|
128
137
|
},
|
|
129
138
|
];
|
|
@@ -253,7 +262,8 @@ const LogDetail = React.memo(() => {
|
|
|
253
262
|
fontSize: 13,
|
|
254
263
|
color: AppColors.primaryBlack,
|
|
255
264
|
lineHeight: 18,
|
|
256
|
-
|
|
265
|
+
flexShrink: 1,
|
|
266
|
+
}}>
|
|
257
267
|
{originFrame?.functionName && originFrame.functionName !== '<anonymous>'
|
|
258
268
|
? `${originFrame.functionName}()`
|
|
259
269
|
: originFrame?.fileName || t('console.consoleLog')}
|
|
@@ -268,11 +278,11 @@ const LogDetail = React.memo(() => {
|
|
|
268
278
|
paddingVertical: 2,
|
|
269
279
|
},
|
|
270
280
|
]}>
|
|
271
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 3 }}>
|
|
281
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 3, flexWrap: 'wrap', flexShrink: 1 }}>
|
|
272
282
|
<DocIcon color={AppColors.brandPurple} size={10}/>
|
|
273
283
|
<Text style={[
|
|
274
284
|
styles.metaChipText,
|
|
275
|
-
{ color: AppColors.brandPurple, fontSize: 10, fontFamily: AppFonts.interBold },
|
|
285
|
+
{ color: AppColors.brandPurple, fontSize: 10, fontFamily: AppFonts.interBold, flexShrink: 1 },
|
|
276
286
|
]}>
|
|
277
287
|
{originFrame.fileName}
|
|
278
288
|
{originFrame.lineNumber ? `:${originFrame.lineNumber}` : ''}
|
|
@@ -575,10 +585,12 @@ const LogDetail = React.memo(() => {
|
|
|
575
585
|
? AppColors.primaryLight
|
|
576
586
|
: AppColors.grayBackground,
|
|
577
587
|
}}>
|
|
588
|
+
{/* Header Top Row: Title, Mode switcher & Full copy */}
|
|
578
589
|
<View style={{
|
|
579
590
|
flexDirection: 'row',
|
|
580
591
|
alignItems: 'center',
|
|
581
592
|
justifyContent: 'space-between',
|
|
593
|
+
gap: 8,
|
|
582
594
|
}}>
|
|
583
595
|
<Text style={{
|
|
584
596
|
fontFamily: AppFonts.interBold,
|
|
@@ -587,156 +599,257 @@ const LogDetail = React.memo(() => {
|
|
|
587
599
|
textTransform: 'uppercase',
|
|
588
600
|
letterSpacing: 0.4,
|
|
589
601
|
}}>
|
|
590
|
-
{stackSource === 'error'
|
|
602
|
+
{stackSource === 'error'
|
|
603
|
+
? t('console.errorStack', { count: parsedStackFrames.length })
|
|
604
|
+
: t('console.callStack', { count: parsedStackFrames.length })}
|
|
591
605
|
</Text>
|
|
592
|
-
|
|
606
|
+
|
|
607
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
|
|
608
|
+
<View style={{
|
|
609
|
+
flexDirection: 'row',
|
|
610
|
+
backgroundColor: isDark ? AppColors.primaryLight : AppColors.white,
|
|
611
|
+
borderRadius: 7,
|
|
612
|
+
padding: 2,
|
|
613
|
+
borderWidth: 1,
|
|
614
|
+
borderColor: AppColors.dividerColor,
|
|
615
|
+
}}>
|
|
616
|
+
<Pressable onPress={() => setStackViewMode('structured')} style={{
|
|
617
|
+
flexDirection: 'row',
|
|
618
|
+
alignItems: 'center',
|
|
619
|
+
gap: 3,
|
|
620
|
+
paddingVertical: 3.5,
|
|
621
|
+
paddingHorizontal: 7,
|
|
622
|
+
borderRadius: 5,
|
|
623
|
+
backgroundColor: stackViewMode === 'structured'
|
|
624
|
+
? AppColors.brandPurple
|
|
625
|
+
: 'transparent',
|
|
626
|
+
}}>
|
|
627
|
+
<LayersIcon color={stackViewMode === 'structured'
|
|
628
|
+
? AppColors.white
|
|
629
|
+
: AppColors.grayTextWeak} size={11}/>
|
|
630
|
+
<Text style={{
|
|
631
|
+
fontFamily: AppFonts.interBold,
|
|
632
|
+
fontSize: 10,
|
|
633
|
+
color: stackViewMode === 'structured'
|
|
634
|
+
? AppColors.white
|
|
635
|
+
: AppColors.grayTextStrong,
|
|
636
|
+
}}>
|
|
637
|
+
{t('console.cardsView')}
|
|
638
|
+
</Text>
|
|
639
|
+
</Pressable>
|
|
640
|
+
|
|
641
|
+
<Pressable onPress={() => setStackViewMode('raw')} style={{
|
|
642
|
+
flexDirection: 'row',
|
|
643
|
+
alignItems: 'center',
|
|
644
|
+
gap: 3,
|
|
645
|
+
paddingVertical: 3.5,
|
|
646
|
+
paddingHorizontal: 7,
|
|
647
|
+
borderRadius: 5,
|
|
648
|
+
backgroundColor: stackViewMode === 'raw'
|
|
649
|
+
? AppColors.brandPurple
|
|
650
|
+
: 'transparent',
|
|
651
|
+
}}>
|
|
652
|
+
<RawIcon color={stackViewMode === 'raw'
|
|
653
|
+
? AppColors.white
|
|
654
|
+
: AppColors.grayTextWeak} size={11}/>
|
|
655
|
+
<Text style={{
|
|
656
|
+
fontFamily: AppFonts.interBold,
|
|
657
|
+
fontSize: 10,
|
|
658
|
+
color: stackViewMode === 'raw'
|
|
659
|
+
? AppColors.white
|
|
660
|
+
: AppColors.grayTextStrong,
|
|
661
|
+
}}>
|
|
662
|
+
{t('console.rawTraceView')}
|
|
663
|
+
</Text>
|
|
664
|
+
</Pressable>
|
|
665
|
+
</View>
|
|
666
|
+
|
|
667
|
+
<CopyButton value={activeStackString} label={t('console.fullStackTrace')}/>
|
|
668
|
+
</View>
|
|
593
669
|
</View>
|
|
594
670
|
|
|
595
671
|
{/* Source Switcher if Error Stack exists */}
|
|
596
672
|
{selectedLog.errorStack && (<SegmentedTabs tabs={[
|
|
597
673
|
{
|
|
598
674
|
key: 'caller',
|
|
599
|
-
label: '
|
|
675
|
+
label: t('console.callOriginStack'),
|
|
600
676
|
},
|
|
601
677
|
{
|
|
602
678
|
key: 'error',
|
|
603
|
-
label: '
|
|
679
|
+
label: t('console.errorThrownStack'),
|
|
604
680
|
},
|
|
605
681
|
]} activeKey={stackSource} onChange={key => setStackSource(key)}/>)}
|
|
606
682
|
|
|
607
|
-
{/*
|
|
683
|
+
{/* Scope Filter Tabs (Full Width) */}
|
|
608
684
|
<SegmentedTabs tabs={[
|
|
609
685
|
{
|
|
610
|
-
key: '
|
|
611
|
-
label: '
|
|
612
|
-
icon: (isActive) => (<LayersIcon color={isActive ? AppColors.white : AppColors.grayTextWeak} size={12}/>),
|
|
686
|
+
key: 'app',
|
|
687
|
+
label: t('console.appCodeScope', { count: appStackFrames.length }),
|
|
613
688
|
},
|
|
614
689
|
{
|
|
615
|
-
key: '
|
|
616
|
-
label: '
|
|
617
|
-
icon: (isActive) => (<RawIcon color={isActive ? AppColors.white : AppColors.grayTextWeak} size={12}/>),
|
|
690
|
+
key: 'all',
|
|
691
|
+
label: t('console.allFramesScope', { count: parsedStackFrames.length }),
|
|
618
692
|
},
|
|
619
|
-
]} activeKey={
|
|
693
|
+
]} activeKey={stackFilter} onChange={key => setStackFilter(key)}/>
|
|
620
694
|
</View>
|
|
621
695
|
|
|
622
696
|
{/* Stack Content: Structured Cards or Raw Full Trace */}
|
|
623
697
|
{stackViewMode === 'structured' ? (<View style={{ padding: 12, gap: 10 }}>
|
|
624
|
-
{
|
|
698
|
+
{displayedFrames.length > 0 ? (displayedFrames.map((frame, frameIdx) => {
|
|
625
699
|
const isTopFrame = frameIdx === 0;
|
|
700
|
+
const frameBadgeBg = frame.frameType === 'app'
|
|
701
|
+
? `${AppColors.brandPurple}15`
|
|
702
|
+
: frame.frameType === 'dependency'
|
|
703
|
+
? `${AppColors.amber500}18`
|
|
704
|
+
: frame.frameType === 'native'
|
|
705
|
+
? `${AppColors.sky500}18`
|
|
706
|
+
: AppColors.grayBorderSecondary;
|
|
707
|
+
const frameBadgeText = frame.frameType === 'app'
|
|
708
|
+
? AppColors.brandPurple
|
|
709
|
+
: frame.frameType === 'dependency'
|
|
710
|
+
? AppColors.amber700
|
|
711
|
+
: frame.frameType === 'native'
|
|
712
|
+
? AppColors.sky500
|
|
713
|
+
: AppColors.grayTextWeak;
|
|
626
714
|
return (<View key={frameIdx} style={{
|
|
627
715
|
backgroundColor: isTopFrame
|
|
628
716
|
? `${AppColors.brandPurple}0A`
|
|
629
717
|
: AppColors.primaryLight,
|
|
630
|
-
borderRadius:
|
|
718
|
+
borderRadius: 10,
|
|
631
719
|
borderWidth: 1,
|
|
632
720
|
borderColor: isTopFrame
|
|
633
|
-
? `${AppColors.brandPurple}
|
|
721
|
+
? `${AppColors.brandPurple}35`
|
|
634
722
|
: AppColors.dividerColor,
|
|
635
|
-
padding:
|
|
636
|
-
gap:
|
|
723
|
+
padding: 11,
|
|
724
|
+
gap: 6,
|
|
637
725
|
}}>
|
|
638
|
-
{/* Frame
|
|
726
|
+
{/* Frame Top Row: Origin / Category, File, Line badge, Copy */}
|
|
639
727
|
<View style={{
|
|
640
728
|
flexDirection: 'row',
|
|
641
729
|
alignItems: 'center',
|
|
642
730
|
justifyContent: 'space-between',
|
|
643
731
|
gap: 6,
|
|
644
732
|
}}>
|
|
645
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', gap:
|
|
646
|
-
<View style={{
|
|
647
|
-
|
|
648
|
-
? AppColors.brandPurple
|
|
649
|
-
: AppColors.grayBorderSecondary,
|
|
650
|
-
borderRadius: 4,
|
|
651
|
-
paddingHorizontal: 5,
|
|
652
|
-
paddingVertical: 1.5,
|
|
653
|
-
}}>
|
|
654
|
-
<Text style={{
|
|
655
|
-
fontFamily: AppFonts.interBold,
|
|
656
|
-
fontSize: 9,
|
|
657
|
-
color: isTopFrame
|
|
658
|
-
? AppColors.white
|
|
659
|
-
: AppColors.grayTextStrong,
|
|
660
|
-
}}>
|
|
661
|
-
#{frameIdx + 1}
|
|
662
|
-
{isTopFrame ? ' ORIGIN' : ''}
|
|
663
|
-
</Text>
|
|
664
|
-
</View>
|
|
665
|
-
|
|
666
|
-
<HighlightText text={frame.functionName !== '<anonymous>' ? `${frame.functionName}()` : '<anonymous>'} search={detailSearch} style={{
|
|
667
|
-
fontFamily: AppFonts.interBold,
|
|
668
|
-
fontSize: 12,
|
|
669
|
-
color: isTopFrame
|
|
670
|
-
? AppColors.primaryBlack
|
|
671
|
-
: AppColors.grayTextStrong,
|
|
672
|
-
}} highlightStyle={{
|
|
673
|
-
backgroundColor: AppColors.yellowHighlight,
|
|
674
|
-
color: AppColors.primaryBlack,
|
|
675
|
-
}}/>
|
|
676
|
-
</View>
|
|
677
|
-
|
|
678
|
-
{frame.lineNumber && (<View style={{
|
|
679
|
-
backgroundColor: `${AppColors.teal600}15`,
|
|
680
|
-
borderColor: `${AppColors.teal600}30`,
|
|
681
|
-
borderWidth: 1,
|
|
733
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 5, flex: 1, flexWrap: 'wrap' }}>
|
|
734
|
+
{isTopFrame && (<View style={{
|
|
735
|
+
backgroundColor: AppColors.brandPurple,
|
|
682
736
|
borderRadius: 4,
|
|
683
|
-
paddingHorizontal:
|
|
737
|
+
paddingHorizontal: 5,
|
|
684
738
|
paddingVertical: 1.5,
|
|
685
739
|
}}>
|
|
686
|
-
|
|
740
|
+
<Text style={{
|
|
687
741
|
fontFamily: AppFonts.interBold,
|
|
688
|
-
fontSize:
|
|
689
|
-
color: AppColors.
|
|
742
|
+
fontSize: 8.5,
|
|
743
|
+
color: AppColors.white,
|
|
690
744
|
}}>
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
</
|
|
694
|
-
</View>)}
|
|
695
|
-
</View>
|
|
745
|
+
{t('console.originBadge')}
|
|
746
|
+
</Text>
|
|
747
|
+
</View>)}
|
|
696
748
|
|
|
697
|
-
|
|
698
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
|
|
699
|
-
{frame.fileExt && frame.fileExt !== 'other' && (<View style={{
|
|
749
|
+
{frame.fileExt && frame.fileExt !== 'other' && (<View style={{
|
|
700
750
|
backgroundColor: frame.fileExt === 'tsx' || frame.fileExt === 'ts'
|
|
701
751
|
? `${AppColors.brandPurple}18`
|
|
702
752
|
: `${AppColors.teal600}18`,
|
|
703
|
-
borderRadius:
|
|
704
|
-
paddingHorizontal: 4,
|
|
705
|
-
paddingVertical: 1,
|
|
753
|
+
borderRadius: 4,
|
|
754
|
+
paddingHorizontal: 4.5,
|
|
755
|
+
paddingVertical: 1.5,
|
|
706
756
|
}}>
|
|
707
|
-
|
|
757
|
+
<Text style={{
|
|
708
758
|
fontFamily: AppFonts.interBold,
|
|
709
759
|
fontSize: 8.5,
|
|
710
760
|
color: frame.fileExt === 'tsx' || frame.fileExt === 'ts'
|
|
711
761
|
? AppColors.brandPurple
|
|
712
762
|
: AppColors.teal600,
|
|
713
763
|
}}>
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
fontSize: 10.5,
|
|
764
|
+
{frame.fileExt.toUpperCase()}
|
|
765
|
+
</Text>
|
|
766
|
+
</View>)}
|
|
767
|
+
|
|
768
|
+
<Text style={{
|
|
769
|
+
fontFamily: AppFonts.interBold,
|
|
770
|
+
fontSize: 11.5,
|
|
722
771
|
color: isTopFrame
|
|
723
772
|
? AppColors.brandPurple
|
|
724
|
-
: AppColors.
|
|
773
|
+
: AppColors.primaryBlack,
|
|
725
774
|
}}>
|
|
726
|
-
|
|
727
|
-
|
|
775
|
+
{frame.fileName}
|
|
776
|
+
</Text>
|
|
777
|
+
</View>
|
|
778
|
+
|
|
779
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
|
|
780
|
+
{frame.lineNumber && (<View style={{
|
|
781
|
+
backgroundColor: `${AppColors.teal600}15`,
|
|
782
|
+
borderColor: `${AppColors.teal600}30`,
|
|
783
|
+
borderWidth: 1,
|
|
784
|
+
borderRadius: 4,
|
|
785
|
+
paddingHorizontal: 5,
|
|
786
|
+
paddingVertical: 1.5,
|
|
787
|
+
}}>
|
|
788
|
+
<Text style={{
|
|
789
|
+
fontFamily: AppFonts.interBold,
|
|
790
|
+
fontSize: 9.5,
|
|
791
|
+
color: AppColors.teal600,
|
|
792
|
+
}}>
|
|
793
|
+
L{frame.lineNumber}{frame.columnNumber ? `:C${frame.columnNumber}` : ''}
|
|
794
|
+
</Text>
|
|
795
|
+
</View>)}
|
|
796
|
+
<CopyButton value={frame.copyableLocation} label={frame.fileName}/>
|
|
797
|
+
</View>
|
|
728
798
|
</View>
|
|
799
|
+
|
|
800
|
+
{/* Middle Row: Function / Symbol Invocation */}
|
|
801
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
|
|
802
|
+
<HighlightText text={frame.functionName !== '<anonymous>' ? `${frame.functionName}()` : '<anonymous>'} search={detailSearch} style={{
|
|
803
|
+
fontFamily: AppFonts.interBold,
|
|
804
|
+
fontSize: 12.5,
|
|
805
|
+
color: AppColors.primaryBlack,
|
|
806
|
+
}} highlightStyle={{
|
|
807
|
+
backgroundColor: AppColors.yellowHighlight,
|
|
808
|
+
color: AppColors.primaryBlack,
|
|
809
|
+
}}/>
|
|
729
810
|
</View>
|
|
730
811
|
|
|
731
|
-
{/*
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
812
|
+
{/* Bottom Row: Clean Relative Path & Execution Scope Tag */}
|
|
813
|
+
<View style={{
|
|
814
|
+
flexDirection: 'row',
|
|
815
|
+
alignItems: 'center',
|
|
816
|
+
justifyContent: 'space-between',
|
|
817
|
+
backgroundColor: isDark ? `${AppColors.primaryBlack}25` : AppColors.grayBackground,
|
|
818
|
+
borderRadius: 6,
|
|
819
|
+
paddingHorizontal: 8,
|
|
820
|
+
paddingVertical: 4.5,
|
|
821
|
+
gap: 6,
|
|
822
|
+
}}>
|
|
823
|
+
<Text selectable style={{
|
|
824
|
+
fontFamily: AppFonts.interRegular,
|
|
825
|
+
fontSize: 9.5,
|
|
826
|
+
color: AppColors.grayTextStrong,
|
|
827
|
+
flex: 1,
|
|
828
|
+
}} numberOfLines={1}>
|
|
829
|
+
📂 {frame.fullPath}
|
|
830
|
+
</Text>
|
|
831
|
+
|
|
832
|
+
<View style={{
|
|
833
|
+
backgroundColor: frameBadgeBg,
|
|
834
|
+
borderRadius: 4,
|
|
835
|
+
paddingHorizontal: 5,
|
|
836
|
+
paddingVertical: 1.5,
|
|
837
|
+
}}>
|
|
838
|
+
<Text style={{
|
|
839
|
+
fontFamily: AppFonts.interBold,
|
|
840
|
+
fontSize: 8.5,
|
|
841
|
+
color: frameBadgeText,
|
|
842
|
+
}}>
|
|
843
|
+
{frame.frameType === 'app'
|
|
844
|
+
? t('console.appCodeBadge')
|
|
845
|
+
: frame.frameType === 'dependency'
|
|
846
|
+
? t('console.dependencyBadge')
|
|
847
|
+
: frame.frameType === 'native'
|
|
848
|
+
? t('console.nativeBadge')
|
|
849
|
+
: t('console.hermesVmBadge')}
|
|
850
|
+
</Text>
|
|
851
|
+
</View>
|
|
852
|
+
</View>
|
|
740
853
|
</View>);
|
|
741
854
|
})) : (<Text style={{
|
|
742
855
|
fontFamily: AppFonts.interRegular,
|
|
@@ -745,7 +858,7 @@ const LogDetail = React.memo(() => {
|
|
|
745
858
|
textAlign: 'center',
|
|
746
859
|
paddingVertical: 16,
|
|
747
860
|
}}>
|
|
748
|
-
|
|
861
|
+
{t('console.noStackAvailable')}
|
|
749
862
|
</Text>)}
|
|
750
863
|
</View>) : (
|
|
751
864
|
/* Raw Full Trace Monospace Block */
|