react-native-inapp-inspector 1.1.1 → 1.1.2
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/dist/commonjs/components/JsonViewer.d.ts +2 -1
- package/dist/commonjs/components/JsonViewer.js +6 -4
- package/dist/commonjs/components/MetaAccordion.js +26 -6
- package/dist/commonjs/components/ReduxTreeView.js +80 -5
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/index.js +342 -141
- package/dist/commonjs/styles/index.d.ts +24 -0
- package/dist/commonjs/styles/index.js +22 -1
- package/dist/esm/components/JsonViewer.d.ts +2 -1
- package/dist/esm/components/JsonViewer.js +6 -4
- package/dist/esm/components/MetaAccordion.js +27 -7
- package/dist/esm/components/ReduxTreeView.js +81 -6
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/index.js +344 -143
- package/dist/esm/styles/index.d.ts +24 -0
- package/dist/esm/styles/index.js +22 -1
- package/example/App.tsx +199 -61
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
|
|
2
|
-
import { Alert, Animated, StyleSheet, FlatList, LayoutAnimation, Modal, Platform, Pressable, ScrollView, Text, TextInput, View, Linking, Image, InteractionManager, ActivityIndicator, StatusBar, TouchableOpacity, UIManager, LogBox, } from 'react-native';
|
|
2
|
+
import { Alert, Animated, StyleSheet, FlatList, LayoutAnimation, Modal, PanResponder, Platform, Pressable, ScrollView, Text, TextInput, View, Linking, Image, InteractionManager, ActivityIndicator, StatusBar, TouchableOpacity, UIManager, LogBox, } from 'react-native';
|
|
3
3
|
import Svg, { Circle, Path } from 'react-native-svg';
|
|
4
4
|
import LinearGradient from 'react-native-linear-gradient';
|
|
5
5
|
import { useNavigationState, NavigationContext } from '@react-navigation/native';
|
|
@@ -24,7 +24,7 @@ import AnimatedEntrance from './components/AnimatedEntrance';
|
|
|
24
24
|
// Helpers
|
|
25
25
|
import { formatDateTime, getStatusColor, getNavigationInfo, deduplicateLogs, getDomainColor, formatDisplayUrl, getFetchCommand, getCurlCommand, getSize, } from './helpers';
|
|
26
26
|
// Assets
|
|
27
|
-
import { EmptyRadarIcon, FailIcon, SearchIcon, ScreenIcon, ClearIcon, SortArrowIcon, FilterIcon, InsightsIcon, GlobeIcon, DownloadIcon, CloseWhite, TrashIcon, WhiteBackNavigation, TerminalIcon, SignalIcon, AnalyticsIcon, SunIcon, MoonIcon, BrandCircleIcon, BrandSquareIcon, HtmlIcon, CssIcon, JsIcon, ClockIcon, EyeIcon, CheckIcon, SettingsIcon, RequestIcon, ResponseIcon, HeadersIcon, StatusIcon, } from './components/NetworkIcons';
|
|
27
|
+
import { EmptyRadarIcon, FailIcon, SearchIcon, ScreenIcon, ClearIcon, SortArrowIcon, FilterIcon, InsightsIcon, GlobeIcon, DownloadIcon, CloseWhite, TrashIcon, WhiteBackNavigation, TerminalIcon, SignalIcon, AnalyticsIcon, SunIcon, MoonIcon, BrandCircleIcon, BrandSquareIcon, HtmlIcon, CssIcon, JsIcon, ClockIcon, EyeIcon, CheckIcon, SettingsIcon, RequestIcon, ResponseIcon, HeadersIcon, StatusIcon, ChevronIcon, } from './components/NetworkIcons';
|
|
28
28
|
import ErrorBoundary from './components/ErrorBoundary';
|
|
29
29
|
// Stylesheet
|
|
30
30
|
import { AppColors } from './styles/AppColors';
|
|
@@ -150,6 +150,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
150
150
|
const [showNetworkMenu, setShowNetworkMenu] = useState(false);
|
|
151
151
|
const [showUiMenu, setShowUiMenu] = useState(false);
|
|
152
152
|
const [sortOrder, setSortOrder] = useState('newest');
|
|
153
|
+
// #7 — sort order for the Logs (console) tab
|
|
154
|
+
const [logSortOrder, setLogSortOrder] = useState('newest');
|
|
153
155
|
const [reqExpanded, setReqExpanded] = useState(undefined);
|
|
154
156
|
const [resExpanded, setResExpanded] = useState(undefined);
|
|
155
157
|
const [showReqDiff, setShowReqDiff] = useState(false);
|
|
@@ -329,6 +331,66 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
329
331
|
const badgeAnim = useRef(new Animated.Value(1)).current;
|
|
330
332
|
const activePulseAnim = useRef(new Animated.Value(0.4)).current;
|
|
331
333
|
const unreadPulseAnim = useRef(new Animated.Value(1)).current;
|
|
334
|
+
// #11 — header "clear all" icon spin/scale animation
|
|
335
|
+
const clearAnim = useRef(new Animated.Value(0)).current;
|
|
336
|
+
// #4 — draggable floating launcher (drag anywhere on screen)
|
|
337
|
+
const fabPan = useRef(new Animated.ValueXY({ x: 0, y: 0 })).current;
|
|
338
|
+
const fabPanRef = useRef({ x: 0, y: 0 });
|
|
339
|
+
useEffect(() => {
|
|
340
|
+
const idX = fabPan.x.addListener(v => (fabPanRef.current.x = v.value));
|
|
341
|
+
const idY = fabPan.y.addListener(v => (fabPanRef.current.y = v.value));
|
|
342
|
+
return () => {
|
|
343
|
+
fabPan.x.removeListener(idX);
|
|
344
|
+
fabPan.y.removeListener(idY);
|
|
345
|
+
};
|
|
346
|
+
}, [fabPan]);
|
|
347
|
+
const fabDraggedRef = useRef(false);
|
|
348
|
+
const fabPanResponder = useRef(PanResponder.create({
|
|
349
|
+
// Let taps fall through to the launcher; only hijack once the
|
|
350
|
+
// finger actually moves, so onPress still fires on a tap.
|
|
351
|
+
onStartShouldSetPanResponder: () => false,
|
|
352
|
+
onMoveShouldSetPanResponder: (_e, g) => Math.abs(g.dx) > 4 || Math.abs(g.dy) > 4,
|
|
353
|
+
onPanResponderGrant: () => {
|
|
354
|
+
fabDraggedRef.current = true;
|
|
355
|
+
fabPan.setOffset({
|
|
356
|
+
x: fabPanRef.current.x,
|
|
357
|
+
y: fabPanRef.current.y,
|
|
358
|
+
});
|
|
359
|
+
fabPan.setValue({ x: 0, y: 0 });
|
|
360
|
+
},
|
|
361
|
+
onPanResponderMove: Animated.event([null, { dx: fabPan.x, dy: fabPan.y }], {
|
|
362
|
+
useNativeDriver: false,
|
|
363
|
+
}),
|
|
364
|
+
onPanResponderRelease: () => {
|
|
365
|
+
fabPan.flattenOffset();
|
|
366
|
+
// small delay so the trailing tap (if any) is ignored
|
|
367
|
+
setTimeout(() => {
|
|
368
|
+
fabDraggedRef.current = false;
|
|
369
|
+
}, 50);
|
|
370
|
+
},
|
|
371
|
+
onPanResponderTerminate: () => {
|
|
372
|
+
fabPan.flattenOffset();
|
|
373
|
+
fabDraggedRef.current = false;
|
|
374
|
+
},
|
|
375
|
+
})).current;
|
|
376
|
+
// #10 — scroll-to-top affordance for the main APIs list
|
|
377
|
+
const apisListRef = useRef(null);
|
|
378
|
+
const [showScrollTop, setShowScrollTop] = useState(false);
|
|
379
|
+
const runClearAllWithAnimation = useCallback(() => {
|
|
380
|
+
Animated.sequence([
|
|
381
|
+
Animated.timing(clearAnim, {
|
|
382
|
+
toValue: 1,
|
|
383
|
+
duration: 320,
|
|
384
|
+
useNativeDriver: true,
|
|
385
|
+
}),
|
|
386
|
+
Animated.timing(clearAnim, {
|
|
387
|
+
toValue: 0,
|
|
388
|
+
duration: 0,
|
|
389
|
+
useNativeDriver: true,
|
|
390
|
+
}),
|
|
391
|
+
]).start();
|
|
392
|
+
handleClearAll();
|
|
393
|
+
}, [clearAnim]);
|
|
332
394
|
useEffect(() => {
|
|
333
395
|
if (Platform.OS === 'android') {
|
|
334
396
|
UIManager.setLayoutAnimationEnabledExperimental?.(true);
|
|
@@ -753,8 +815,12 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
753
815
|
result = result.filter(log => log.message.toLowerCase().includes(s) ||
|
|
754
816
|
(log.caller ?? '').toLowerCase().includes(s));
|
|
755
817
|
}
|
|
818
|
+
// #7 — apply sort order (newest/oldest first)
|
|
819
|
+
result = [...result].sort((a, b) => logSortOrder === 'newest'
|
|
820
|
+
? b.timestamp - a.timestamp
|
|
821
|
+
: a.timestamp - b.timestamp);
|
|
756
822
|
return result;
|
|
757
|
-
}, [visibleConsoleLogs, logFilters, logSearch]);
|
|
823
|
+
}, [visibleConsoleLogs, logFilters, logSearch, logSortOrder]);
|
|
758
824
|
const filteredWebViewLogs = useMemo(() => {
|
|
759
825
|
let result = webViewLogs;
|
|
760
826
|
if (webViewSearch) {
|
|
@@ -880,6 +946,22 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
880
946
|
]);
|
|
881
947
|
return;
|
|
882
948
|
}
|
|
949
|
+
if (activeTab === 'redux') {
|
|
950
|
+
Alert.alert('Clear Redux Timeline', 'Are you sure you want to clear the dispatched action history?', [
|
|
951
|
+
{ text: 'Cancel', style: 'cancel' },
|
|
952
|
+
{
|
|
953
|
+
text: 'Clear All',
|
|
954
|
+
onPress: () => {
|
|
955
|
+
clearActionHistory();
|
|
956
|
+
setReduxActionHistory([]);
|
|
957
|
+
setReduxLastActionMap({});
|
|
958
|
+
},
|
|
959
|
+
style: 'destructive',
|
|
960
|
+
},
|
|
961
|
+
]);
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
// Default: APIs tab. Only clears NETWORK logs — never touches the other tabs.
|
|
883
965
|
if (selectedLogs.size > 0) {
|
|
884
966
|
setLogs(prev => prev.filter(l => !selectedLogs.has(l.id)));
|
|
885
967
|
setSelectedLogs(new Set());
|
|
@@ -887,10 +969,22 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
887
969
|
else {
|
|
888
970
|
Alert.alert('Clear Logs', 'Are you sure you want to clear all network logs?', [
|
|
889
971
|
{ text: 'Cancel', style: 'cancel' },
|
|
890
|
-
{ text: 'Clear All', onPress:
|
|
972
|
+
{ text: 'Clear All', onPress: clearNetworkOnly, style: 'destructive' },
|
|
891
973
|
]);
|
|
892
974
|
}
|
|
893
975
|
}
|
|
976
|
+
// Clears ONLY network logs + their derived selection/filter state.
|
|
977
|
+
function clearNetworkOnly() {
|
|
978
|
+
clearNetworkLogs();
|
|
979
|
+
setLogs([]);
|
|
980
|
+
setSelectedLogs(new Set());
|
|
981
|
+
setSectionFilters({});
|
|
982
|
+
setCollapsedSections(new Set());
|
|
983
|
+
setStatusFilters(new Set());
|
|
984
|
+
setMethodFilters(new Set());
|
|
985
|
+
prevLogIdsRef.current = new Set();
|
|
986
|
+
logRouteMapRef.current = new Map();
|
|
987
|
+
}
|
|
894
988
|
const detailTitle = useMemo(() => {
|
|
895
989
|
if (!selected)
|
|
896
990
|
return '';
|
|
@@ -1224,7 +1318,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1224
1318
|
})}
|
|
1225
1319
|
</View>
|
|
1226
1320
|
|
|
1227
|
-
{/* Preferences Section */}
|
|
1321
|
+
{/* UI Preferences Section */}
|
|
1228
1322
|
<View style={{ marginTop: 8 }}>
|
|
1229
1323
|
<Text style={{
|
|
1230
1324
|
fontFamily: AppFonts.interBold,
|
|
@@ -1233,7 +1327,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1233
1327
|
letterSpacing: 0.6,
|
|
1234
1328
|
marginBottom: 8,
|
|
1235
1329
|
}}>
|
|
1236
|
-
PREFERENCES
|
|
1330
|
+
UI PREFERENCES
|
|
1237
1331
|
</Text>
|
|
1238
1332
|
<View style={{
|
|
1239
1333
|
backgroundColor: AppColors.primaryLight,
|
|
@@ -2489,50 +2583,6 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2489
2583
|
const lastActionMap = reduxLastActionMap;
|
|
2490
2584
|
const actionHistory = reduxActionHistory;
|
|
2491
2585
|
return (<ScrollView style={styles.detailScroll} contentContainerStyle={{ paddingBottom: 24 }}>
|
|
2492
|
-
{/* Top Summary Card */}
|
|
2493
|
-
<View style={{
|
|
2494
|
-
backgroundColor: AppColors.primaryLight,
|
|
2495
|
-
borderRadius: 12,
|
|
2496
|
-
borderWidth: 1,
|
|
2497
|
-
borderColor: AppColors.grayBorderSecondary,
|
|
2498
|
-
padding: 14,
|
|
2499
|
-
marginHorizontal: 16,
|
|
2500
|
-
marginTop: 12,
|
|
2501
|
-
marginBottom: 12,
|
|
2502
|
-
flexDirection: 'row',
|
|
2503
|
-
alignItems: 'center',
|
|
2504
|
-
gap: 12,
|
|
2505
|
-
}}>
|
|
2506
|
-
<View style={{
|
|
2507
|
-
width: 44,
|
|
2508
|
-
height: 44,
|
|
2509
|
-
borderRadius: 10,
|
|
2510
|
-
backgroundColor: AppColors.purpleShade50,
|
|
2511
|
-
alignItems: 'center',
|
|
2512
|
-
justifyContent: 'center',
|
|
2513
|
-
}}>
|
|
2514
|
-
<TerminalIcon color={AppColors.purple} size={20}/>
|
|
2515
|
-
</View>
|
|
2516
|
-
<View style={{ flex: 1 }}>
|
|
2517
|
-
<Text style={{
|
|
2518
|
-
fontFamily: AppFonts.interBold,
|
|
2519
|
-
fontSize: 13,
|
|
2520
|
-
color: AppColors.primaryBlack,
|
|
2521
|
-
}}>
|
|
2522
|
-
Redux Store Snapshot
|
|
2523
|
-
</Text>
|
|
2524
|
-
<Text style={{
|
|
2525
|
-
fontFamily: AppFonts.interRegular,
|
|
2526
|
-
fontSize: 11,
|
|
2527
|
-
color: AppColors.grayText,
|
|
2528
|
-
marginTop: 2,
|
|
2529
|
-
}}>
|
|
2530
|
-
Total size: {getSize(reduxState)} • {reducerKeys.length} Reducers
|
|
2531
|
-
</Text>
|
|
2532
|
-
</View>
|
|
2533
|
-
<CopyButton value={() => reduxState} label="Overall Store"/>
|
|
2534
|
-
</View>
|
|
2535
|
-
|
|
2536
2586
|
{/* Tab View Selection Segments */}
|
|
2537
2587
|
<View style={{
|
|
2538
2588
|
flexDirection: 'row',
|
|
@@ -2540,6 +2590,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2540
2590
|
borderRadius: 10,
|
|
2541
2591
|
padding: 3,
|
|
2542
2592
|
marginHorizontal: 16,
|
|
2593
|
+
marginTop: 12,
|
|
2543
2594
|
marginBottom: 12,
|
|
2544
2595
|
borderWidth: 1,
|
|
2545
2596
|
borderColor: AppColors.dividerColor,
|
|
@@ -2575,6 +2626,27 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2575
2626
|
}}>
|
|
2576
2627
|
Action Timeline
|
|
2577
2628
|
</Text>
|
|
2629
|
+
<View style={{
|
|
2630
|
+
minWidth: 18,
|
|
2631
|
+
paddingHorizontal: 5,
|
|
2632
|
+
height: 16,
|
|
2633
|
+
borderRadius: 8,
|
|
2634
|
+
alignItems: 'center',
|
|
2635
|
+
justifyContent: 'center',
|
|
2636
|
+
backgroundColor: reduxActiveSubTab === 'timeline'
|
|
2637
|
+
? 'rgba(255,255,255,0.28)'
|
|
2638
|
+
: AppColors.dividerColor,
|
|
2639
|
+
}}>
|
|
2640
|
+
<Text style={{
|
|
2641
|
+
fontFamily: AppFonts.interBold,
|
|
2642
|
+
fontSize: 9,
|
|
2643
|
+
color: reduxActiveSubTab === 'timeline'
|
|
2644
|
+
? '#FFFFFF'
|
|
2645
|
+
: AppColors.grayText,
|
|
2646
|
+
}}>
|
|
2647
|
+
{actionHistory.length}
|
|
2648
|
+
</Text>
|
|
2649
|
+
</View>
|
|
2578
2650
|
</View>
|
|
2579
2651
|
</TouchableOpacity>
|
|
2580
2652
|
<TouchableOpacity onPress={() => {
|
|
@@ -2604,6 +2676,27 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2604
2676
|
}}>
|
|
2605
2677
|
Store Tree
|
|
2606
2678
|
</Text>
|
|
2679
|
+
<View style={{
|
|
2680
|
+
minWidth: 18,
|
|
2681
|
+
paddingHorizontal: 5,
|
|
2682
|
+
height: 16,
|
|
2683
|
+
borderRadius: 8,
|
|
2684
|
+
alignItems: 'center',
|
|
2685
|
+
justifyContent: 'center',
|
|
2686
|
+
backgroundColor: reduxActiveSubTab === 'tree'
|
|
2687
|
+
? 'rgba(255,255,255,0.28)'
|
|
2688
|
+
: AppColors.dividerColor,
|
|
2689
|
+
}}>
|
|
2690
|
+
<Text style={{
|
|
2691
|
+
fontFamily: AppFonts.interBold,
|
|
2692
|
+
fontSize: 9,
|
|
2693
|
+
color: reduxActiveSubTab === 'tree'
|
|
2694
|
+
? '#FFFFFF'
|
|
2695
|
+
: AppColors.grayText,
|
|
2696
|
+
}}>
|
|
2697
|
+
{reducerKeys.length}
|
|
2698
|
+
</Text>
|
|
2699
|
+
</View>
|
|
2607
2700
|
</View>
|
|
2608
2701
|
</TouchableOpacity>
|
|
2609
2702
|
</View>
|
|
@@ -2650,21 +2743,27 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2650
2743
|
};
|
|
2651
2744
|
return (<>
|
|
2652
2745
|
{hasNavigationContext && (<NavigationTracker onStateChange={setNavState}/>)}
|
|
2653
|
-
<
|
|
2654
|
-
<
|
|
2655
|
-
|
|
2656
|
-
|
|
2746
|
+
<Animated.View style={[styles.fabWrapper, { transform: fabPan.getTranslateTransform() }]} {...fabPanResponder.panHandlers}>
|
|
2747
|
+
<TouchableScale style={{ alignItems: 'center', justifyContent: 'center' }} onPress={() => {
|
|
2748
|
+
if (fabDraggedRef.current)
|
|
2749
|
+
return;
|
|
2750
|
+
setVisible(true);
|
|
2751
|
+
}} hitSlop={10}>
|
|
2752
|
+
<Animated.View style={[styles.fabPulseRing, { transform: [{ scale: pulseAnim }] }]}/>
|
|
2753
|
+
<BrandCircleIcon size={62}/>
|
|
2754
|
+
{(logs.length > 0 || analyticsEvents.length > 0) && (<Animated.View style={[
|
|
2657
2755
|
styles.fabBadge,
|
|
2658
2756
|
hasErrors ? styles.fabBadgeError : styles.fabBadgeNormal,
|
|
2659
2757
|
{ transform: [{ scale: badgeAnim }] },
|
|
2660
2758
|
]}>
|
|
2661
|
-
|
|
2662
|
-
|
|
2759
|
+
<Text style={styles.fabBadgeText}>
|
|
2760
|
+
{logs.length + analyticsEvents.length > 99
|
|
2663
2761
|
? '99+'
|
|
2664
2762
|
: logs.length + analyticsEvents.length}
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2763
|
+
</Text>
|
|
2764
|
+
</Animated.View>)}
|
|
2765
|
+
</TouchableScale>
|
|
2766
|
+
</Animated.View>
|
|
2668
2767
|
|
|
2669
2768
|
<Modal visible={visible} animationType="slide" transparent>
|
|
2670
2769
|
{visible && (<ErrorBoundary onClose={closeModal}>
|
|
@@ -2694,10 +2793,27 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2694
2793
|
setSelectedEvent(null);
|
|
2695
2794
|
});
|
|
2696
2795
|
}} hitSlop={15} style={[
|
|
2697
|
-
|
|
2796
|
+
{
|
|
2797
|
+
width: 38,
|
|
2798
|
+
height: 38,
|
|
2799
|
+
borderRadius: 19,
|
|
2800
|
+
alignItems: 'center',
|
|
2801
|
+
justifyContent: 'center',
|
|
2802
|
+
backgroundColor: 'rgba(255,255,255,0.18)',
|
|
2803
|
+
borderWidth: 1,
|
|
2804
|
+
borderColor: 'rgba(255,255,255,0.30)',
|
|
2805
|
+
},
|
|
2698
2806
|
selected == null &&
|
|
2699
2807
|
selectedEvent == null && { display: 'none' },
|
|
2700
2808
|
]}>
|
|
2809
|
+
{/* Soft outer glow to fake a blurred circle */}
|
|
2810
|
+
<View style={{
|
|
2811
|
+
position: 'absolute',
|
|
2812
|
+
width: 48,
|
|
2813
|
+
height: 48,
|
|
2814
|
+
borderRadius: 24,
|
|
2815
|
+
backgroundColor: 'rgba(255,255,255,0.10)',
|
|
2816
|
+
}}/>
|
|
2701
2817
|
<WhiteBackNavigation />
|
|
2702
2818
|
</TouchableScale>
|
|
2703
2819
|
|
|
@@ -2708,8 +2824,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2708
2824
|
flex: 1,
|
|
2709
2825
|
}}>
|
|
2710
2826
|
<View style={{
|
|
2711
|
-
width:
|
|
2712
|
-
height:
|
|
2827
|
+
width: 50,
|
|
2828
|
+
height: 50,
|
|
2713
2829
|
borderRadius: 10,
|
|
2714
2830
|
backgroundColor: 'rgba(255,255,255,0.13)',
|
|
2715
2831
|
borderWidth: 1.5,
|
|
@@ -2721,13 +2837,10 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2721
2837
|
shadowRadius: 4,
|
|
2722
2838
|
shadowOffset: { width: 0, height: 2 },
|
|
2723
2839
|
}}>
|
|
2724
|
-
<BrandSquareIcon size={
|
|
2840
|
+
<BrandSquareIcon size={45}/>
|
|
2725
2841
|
</View>
|
|
2726
2842
|
<View style={{ gap: 3 }}>
|
|
2727
|
-
<Text style={[
|
|
2728
|
-
styles.headerTitle,
|
|
2729
|
-
{ fontSize: 17, letterSpacing: 0.2 },
|
|
2730
|
-
]}>
|
|
2843
|
+
<Text style={[styles.headerTitle]}>
|
|
2731
2844
|
RN InApp Inspector
|
|
2732
2845
|
</Text>
|
|
2733
2846
|
<View style={{
|
|
@@ -2834,21 +2947,48 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2834
2947
|
</Text>
|
|
2835
2948
|
</View>
|
|
2836
2949
|
<View style={styles.headerDetailSubRow}>
|
|
2837
|
-
<View style={
|
|
2950
|
+
<View style={{
|
|
2951
|
+
flexDirection: 'row',
|
|
2952
|
+
alignItems: 'center',
|
|
2953
|
+
gap: 5,
|
|
2954
|
+
paddingHorizontal: 8,
|
|
2955
|
+
paddingVertical: 3,
|
|
2956
|
+
borderRadius: 20,
|
|
2957
|
+
backgroundColor: `${getStatusColor(selected.status)}26`,
|
|
2958
|
+
borderWidth: 1,
|
|
2959
|
+
borderColor: `${getStatusColor(selected.status)}55`,
|
|
2960
|
+
}}>
|
|
2961
|
+
<View style={[
|
|
2838
2962
|
styles.headerStatusDot,
|
|
2839
2963
|
{
|
|
2840
2964
|
backgroundColor: getStatusColor(selected.status),
|
|
2841
2965
|
},
|
|
2842
2966
|
]}/>
|
|
2843
|
-
|
|
2844
|
-
|
|
2967
|
+
<Text style={[
|
|
2968
|
+
styles.headerSubTitle,
|
|
2969
|
+
{ fontFamily: AppFonts.interBold },
|
|
2970
|
+
]}>
|
|
2971
|
+
{selected.status === 0
|
|
2845
2972
|
? 'Failed'
|
|
2846
|
-
: selected.status ?? 'Pending'}
|
|
2847
|
-
|
|
2848
|
-
|
|
2973
|
+
: selected.status ?? 'Pending'}
|
|
2974
|
+
</Text>
|
|
2975
|
+
</View>
|
|
2976
|
+
<View style={{
|
|
2977
|
+
flexDirection: 'row',
|
|
2978
|
+
alignItems: 'center',
|
|
2979
|
+
gap: 4,
|
|
2980
|
+
paddingHorizontal: 8,
|
|
2981
|
+
paddingVertical: 3,
|
|
2982
|
+
borderRadius: 20,
|
|
2983
|
+
backgroundColor: 'rgba(255,255,255,0.16)',
|
|
2984
|
+
}}>
|
|
2985
|
+
<ClockIcon color="#FFFFFF" size={11}/>
|
|
2986
|
+
<Text style={styles.headerSubTitle}>
|
|
2987
|
+
{selected.duration != null
|
|
2849
2988
|
? `${selected.duration}ms`
|
|
2850
|
-
: '
|
|
2851
|
-
|
|
2989
|
+
: '—'}
|
|
2990
|
+
</Text>
|
|
2991
|
+
</View>
|
|
2852
2992
|
</View>
|
|
2853
2993
|
</View>) : selectedEvent != null ? (<View style={styles.headerDetailCenter}>
|
|
2854
2994
|
<View style={styles.headerDetailRow}>
|
|
@@ -2891,7 +3031,50 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2891
3031
|
</View>) : null}
|
|
2892
3032
|
</View>
|
|
2893
3033
|
|
|
2894
|
-
<View style={
|
|
3034
|
+
<View style={[
|
|
3035
|
+
styles.headerRight,
|
|
3036
|
+
selected == null &&
|
|
3037
|
+
selectedEvent == null && {
|
|
3038
|
+
flexShrink: 0,
|
|
3039
|
+
minWidth: 116,
|
|
3040
|
+
},
|
|
3041
|
+
]}>
|
|
3042
|
+
{selected == null && selectedEvent == null && (<TouchableScale onPress={() => {
|
|
3043
|
+
Alert.alert('Clear Everything', 'This clears all tabs — APIs, Logs, Analytics, WebView and Redux timeline. Continue?', [
|
|
3044
|
+
{ text: 'Cancel', style: 'cancel' },
|
|
3045
|
+
{
|
|
3046
|
+
text: 'Clear All',
|
|
3047
|
+
onPress: runClearAllWithAnimation,
|
|
3048
|
+
style: 'destructive',
|
|
3049
|
+
},
|
|
3050
|
+
]);
|
|
3051
|
+
}} hitSlop={15} style={[
|
|
3052
|
+
styles.closeButtonSquare,
|
|
3053
|
+
{
|
|
3054
|
+
marginRight: 8,
|
|
3055
|
+
backgroundColor: 'rgba(255,255,255,0.15)',
|
|
3056
|
+
},
|
|
3057
|
+
]}>
|
|
3058
|
+
<Animated.View style={{
|
|
3059
|
+
transform: [
|
|
3060
|
+
{
|
|
3061
|
+
rotate: clearAnim.interpolate({
|
|
3062
|
+
inputRange: [0, 1],
|
|
3063
|
+
outputRange: ['0deg', '-25deg'],
|
|
3064
|
+
}),
|
|
3065
|
+
},
|
|
3066
|
+
{
|
|
3067
|
+
scale: clearAnim.interpolate({
|
|
3068
|
+
inputRange: [0, 0.5, 1],
|
|
3069
|
+
outputRange: [1, 1.25, 1],
|
|
3070
|
+
}),
|
|
3071
|
+
},
|
|
3072
|
+
],
|
|
3073
|
+
}}>
|
|
3074
|
+
<TrashIcon color="#FFFFFF" size={15}/>
|
|
3075
|
+
</Animated.View>
|
|
3076
|
+
</TouchableScale>)}
|
|
3077
|
+
|
|
2895
3078
|
{selected == null && selectedEvent == null && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={[
|
|
2896
3079
|
styles.closeButtonSquare,
|
|
2897
3080
|
{
|
|
@@ -3226,50 +3409,53 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3226
3409
|
filteredAnalyticsEvents.length === 0 && {
|
|
3227
3410
|
flexGrow: 1,
|
|
3228
3411
|
},
|
|
3229
|
-
]} keyboardShouldPersistTaps="handled"/>)) : activeTab === 'apis' && selected == null ? (<
|
|
3230
|
-
|
|
3231
|
-
<View style={styles.
|
|
3232
|
-
<
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3412
|
+
]} keyboardShouldPersistTaps="handled"/>)) : activeTab === 'apis' && selected == null ? (<View style={{ flex: 1 }}>
|
|
3413
|
+
<FlatList ref={apisListRef} onScroll={e => setShowScrollTop(e.nativeEvent.contentOffset.y > 320)} scrollEventThrottle={16} data={groupedData} keyExtractor={item => item?.id?.toString()} renderItem={renderItem} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={true} ListHeaderComponent={<View style={{ marginTop: 8 }}>
|
|
3414
|
+
<View style={styles.toolbarRow}>
|
|
3415
|
+
<View style={styles.searchContainer}>
|
|
3416
|
+
<SearchIcon color={AppColors.grayTextWeak} size={16}/>
|
|
3417
|
+
<TextInput placeholder="Search endpoints..." placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={styles.searchInput} autoCorrect={false} autoCapitalize="none"/>
|
|
3418
|
+
{search.length > 0 && (<Pressable onPress={() => setSearch('')} hitSlop={10} style={styles.clearBtn}>
|
|
3419
|
+
<ClearIcon color={AppColors.grayTextWeak} size={14}/>
|
|
3420
|
+
</Pressable>)}
|
|
3421
|
+
</View>
|
|
3238
3422
|
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3423
|
+
<View style={styles.toolbarRight}>
|
|
3424
|
+
<TouchableScale style={styles.toolbarBtn} onPress={handleDelete} hitSlop={10}>
|
|
3425
|
+
<TrashIcon color={AppColors.grayTextStrong} size={18}/>
|
|
3426
|
+
{selectedLogs.size > 0 && (<View style={styles.trashBadge}>
|
|
3427
|
+
<Text style={styles.trashBadgeText}>
|
|
3428
|
+
{selectedLogs.size}
|
|
3429
|
+
</Text>
|
|
3430
|
+
</View>)}
|
|
3431
|
+
</TouchableScale>
|
|
3248
3432
|
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3433
|
+
<TouchableScale style={styles.toolbarBtn} onPress={() => setSortOrder(o => o === 'newest' ? 'oldest' : 'newest')} hitSlop={10}>
|
|
3434
|
+
<SortArrowIcon direction={sortOrder === 'newest' ? 'down' : 'up'} color={AppColors.grayTextStrong} size={18}/>
|
|
3435
|
+
</TouchableScale>
|
|
3252
3436
|
|
|
3253
|
-
|
|
3437
|
+
<TouchableScale style={[
|
|
3254
3438
|
styles.toolbarBtn,
|
|
3255
3439
|
filtersAccordion.isOpen &&
|
|
3256
3440
|
styles.toolbarBtnActive,
|
|
3257
3441
|
]} onPress={filtersAccordion.toggleOpen} hitSlop={10}>
|
|
3258
|
-
|
|
3442
|
+
<FilterIcon color={filtersAccordion.isOpen
|
|
3259
3443
|
? AppColors.purple
|
|
3260
3444
|
: AppColors.grayTextStrong} size={18}/>
|
|
3261
|
-
|
|
3445
|
+
</TouchableScale>
|
|
3446
|
+
</View>
|
|
3262
3447
|
</View>
|
|
3263
|
-
</View>
|
|
3264
3448
|
|
|
3265
|
-
|
|
3449
|
+
<Animated.View style={[
|
|
3266
3450
|
filtersAccordion.bodyStyle,
|
|
3267
3451
|
{ overflow: 'hidden' },
|
|
3268
3452
|
]}>
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3453
|
+
<View style={styles.filtersContainer}>
|
|
3454
|
+
<Text style={styles.filtersHeading}>
|
|
3455
|
+
STATUS
|
|
3456
|
+
</Text>
|
|
3457
|
+
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.statusRowContent}>
|
|
3458
|
+
{STATUS_FILTERS.map(filter => {
|
|
3273
3459
|
const isAll = filter === 'ALL';
|
|
3274
3460
|
const active = isAll
|
|
3275
3461
|
? statusFilters.size === 0
|
|
@@ -3288,38 +3474,38 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3288
3474
|
});
|
|
3289
3475
|
}
|
|
3290
3476
|
}} hitSlop={10}>
|
|
3291
|
-
|
|
3477
|
+
{active ? (<View style={[
|
|
3292
3478
|
styles.statusFilterChip,
|
|
3293
3479
|
styles.statusFilterActive,
|
|
3294
3480
|
{ overflow: 'hidden' },
|
|
3295
3481
|
]}>
|
|
3296
|
-
|
|
3482
|
+
<LinearGradient colors={[
|
|
3297
3483
|
AppColors.purpleShade50,
|
|
3298
3484
|
'#EAE5FF',
|
|
3299
3485
|
]} style={StyleSheet.absoluteFill} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }}/>
|
|
3300
|
-
|
|
3486
|
+
<Text style={[
|
|
3301
3487
|
styles.statusFilterText,
|
|
3302
3488
|
{ color: AppColors.purple },
|
|
3303
3489
|
]}>
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3490
|
+
{filter}
|
|
3491
|
+
</Text>
|
|
3492
|
+
</View>) : (<View style={styles.statusFilterChip}>
|
|
3493
|
+
<Text style={styles.statusFilterText}>
|
|
3494
|
+
{filter}
|
|
3495
|
+
</Text>
|
|
3496
|
+
</View>)}
|
|
3497
|
+
</TouchableScale>);
|
|
3312
3498
|
})}
|
|
3313
|
-
|
|
3499
|
+
</ScrollView>
|
|
3314
3500
|
|
|
3315
|
-
|
|
3501
|
+
<Text style={[
|
|
3316
3502
|
styles.filtersHeading,
|
|
3317
3503
|
{ marginTop: 16 },
|
|
3318
3504
|
]}>
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3505
|
+
METHOD
|
|
3506
|
+
</Text>
|
|
3507
|
+
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.statusRowContent}>
|
|
3508
|
+
{availableMethods.map(filter => {
|
|
3323
3509
|
const isAll = filter === 'ALL';
|
|
3324
3510
|
const active = isAll
|
|
3325
3511
|
? methodFilters.size === 0
|
|
@@ -3338,43 +3524,55 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3338
3524
|
});
|
|
3339
3525
|
}
|
|
3340
3526
|
}} hitSlop={10}>
|
|
3341
|
-
|
|
3527
|
+
{active ? (<View style={[
|
|
3342
3528
|
styles.statusFilterChip,
|
|
3343
3529
|
styles.statusFilterActive,
|
|
3344
3530
|
{ overflow: 'hidden' },
|
|
3345
3531
|
]}>
|
|
3346
|
-
|
|
3532
|
+
<LinearGradient colors={[
|
|
3347
3533
|
AppColors.purpleShade50,
|
|
3348
3534
|
'#EAE5FF',
|
|
3349
3535
|
]} style={StyleSheet.absoluteFill} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }}/>
|
|
3350
|
-
|
|
3536
|
+
<Text style={[
|
|
3351
3537
|
styles.statusFilterText,
|
|
3352
3538
|
{ color: AppColors.purple },
|
|
3353
3539
|
]}>
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3540
|
+
{filter}
|
|
3541
|
+
</Text>
|
|
3542
|
+
</View>) : (<View style={styles.statusFilterChip}>
|
|
3543
|
+
<Text style={styles.statusFilterText}>
|
|
3544
|
+
{filter}
|
|
3545
|
+
</Text>
|
|
3546
|
+
</View>)}
|
|
3547
|
+
</TouchableScale>);
|
|
3362
3548
|
})}
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3549
|
+
</ScrollView>
|
|
3550
|
+
</View>
|
|
3551
|
+
</Animated.View>
|
|
3366
3552
|
|
|
3367
|
-
|
|
3553
|
+
{(search ||
|
|
3368
3554
|
statusFilters.size > 0 ||
|
|
3369
3555
|
methodFilters.size > 0) && (<Text style={styles.resultCount}>
|
|
3370
|
-
|
|
3556
|
+
{filteredLogs.length === logs.length
|
|
3371
3557
|
? `${logs.length} requests`
|
|
3372
3558
|
: `${filteredLogs.length} of ${logs.length} filtered requests`}
|
|
3373
|
-
|
|
3374
|
-
|
|
3559
|
+
</Text>)}
|
|
3560
|
+
</View>} ListEmptyComponent={<EmptyState isSearch={search.length > 0 || statusFilters.size > 0}/>} contentContainerStyle={[
|
|
3375
3561
|
styles.listContent,
|
|
3376
3562
|
filteredLogs.length === 0 && { flexGrow: 1 },
|
|
3377
|
-
]} keyboardShouldPersistTaps="handled"/>
|
|
3563
|
+
]} keyboardShouldPersistTaps="handled"/>
|
|
3564
|
+
{showScrollTop && (<TouchableScale onPress={() => {
|
|
3565
|
+
apisListRef.current?.scrollToOffset({
|
|
3566
|
+
offset: 0,
|
|
3567
|
+
animated: true,
|
|
3568
|
+
});
|
|
3569
|
+
setShowScrollTop(false);
|
|
3570
|
+
}} hitSlop={10} style={styles.scrollTopBtn}>
|
|
3571
|
+
<View style={{ transform: [{ rotate: '180deg' }] }}>
|
|
3572
|
+
<ChevronIcon color="#FFFFFF" size={18}/>
|
|
3573
|
+
</View>
|
|
3574
|
+
</TouchableScale>)}
|
|
3575
|
+
</View>) : activeTab === 'logs' ? (<View style={{ flex: 1 }}>
|
|
3378
3576
|
<View style={{
|
|
3379
3577
|
backgroundColor: '#FFFFFF',
|
|
3380
3578
|
borderBottomWidth: 1,
|
|
@@ -3394,6 +3592,9 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3394
3592
|
</View>
|
|
3395
3593
|
|
|
3396
3594
|
<View style={styles.toolbarRight}>
|
|
3595
|
+
<TouchableScale style={styles.toolbarBtn} onPress={() => setLogSortOrder(o => o === 'newest' ? 'oldest' : 'newest')} hitSlop={10}>
|
|
3596
|
+
<SortArrowIcon color={AppColors.grayTextStrong} size={18} direction={logSortOrder === 'newest' ? 'down' : 'up'}/>
|
|
3597
|
+
</TouchableScale>
|
|
3397
3598
|
<TouchableScale style={styles.toolbarBtn} onPress={handleDelete} hitSlop={10}>
|
|
3398
3599
|
<TrashIcon color={AppColors.grayTextStrong} size={18}/>
|
|
3399
3600
|
</TouchableScale>
|
|
@@ -4633,7 +4834,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
4633
4834
|
if (!resExpanded && !showResDiff)
|
|
4634
4835
|
setResExpanded(true);
|
|
4635
4836
|
}}/>
|
|
4636
|
-
{showResDiff ? (<DiffViewer oldData={prevResponseData} newData={selected.response} forceOpen={resExpanded}/>) : (<JsonViewer data={selected.response} search={detailSearch} forceOpen={resExpanded}/>)}
|
|
4837
|
+
{showResDiff ? (<DiffViewer oldData={prevResponseData} newData={selected.response} forceOpen={resExpanded}/>) : (<JsonViewer data={selected.response} search={detailSearch} forceOpen={resExpanded} wrap/>)}
|
|
4637
4838
|
</View>
|
|
4638
4839
|
</>)}
|
|
4639
4840
|
</ScrollView>
|