react-native-inapp-inspector 1.1.0 → 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/README.md +42 -40
- 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.d.ts +4 -0
- package/dist/commonjs/components/ReduxTreeView.js +115 -10
- package/dist/commonjs/constants/index.d.ts +1 -0
- package/dist/commonjs/constants/index.js +5 -1
- package/dist/commonjs/constants/version.d.ts +1 -0
- package/dist/commonjs/constants/version.js +6 -0
- package/dist/commonjs/customHooks/reduxLogger.js +9 -1
- package/dist/commonjs/index.js +830 -181
- 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.d.ts +4 -0
- package/dist/esm/components/ReduxTreeView.js +111 -10
- package/dist/esm/constants/index.d.ts +1 -0
- package/dist/esm/constants/index.js +3 -0
- package/dist/esm/constants/version.d.ts +1 -0
- package/dist/esm/constants/version.js +3 -0
- package/dist/esm/customHooks/reduxLogger.js +9 -1
- package/dist/esm/index.js +834 -185
- package/dist/esm/styles/index.d.ts +24 -0
- package/dist/esm/styles/index.js +22 -1
- package/example/App.tsx +199 -61
- package/example/ios/example.xcodeproj/project.pbxproj +10 -0
- package/package.json +2 -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';
|
|
@@ -11,7 +11,7 @@ import CopyButton from './components/CopyButton';
|
|
|
11
11
|
import SectionHeader from './components/SectionHeader';
|
|
12
12
|
import EmptyState from './components/EmptyState';
|
|
13
13
|
import JsonViewer from './components/JsonViewer';
|
|
14
|
-
import { ReduxTreeView, ReduxActionTimeline } from './components/ReduxTreeView';
|
|
14
|
+
import { ReduxTreeView, ReduxActionTimeline, ReduxTimelineIcon, ReduxTreeIcon, } from './components/ReduxTreeView';
|
|
15
15
|
import DomainHeader from './components/DomainHeader';
|
|
16
16
|
import DiffViewer from './components/DiffViewer';
|
|
17
17
|
import LogCard from './components/LogCard';
|
|
@@ -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';
|
|
@@ -100,7 +100,7 @@ const previewInspectScript = `
|
|
|
100
100
|
true;
|
|
101
101
|
`;
|
|
102
102
|
import { getReduxState, subscribeReduxState, setReduxAutoRefresh, getLastActionForReducer, getActionHistory, clearActionHistory, } from './customHooks/reduxLogger';
|
|
103
|
-
import { METHOD_COLORS, STATUS_FILTERS } from './constants';
|
|
103
|
+
import { METHOD_COLORS, STATUS_FILTERS, LIB_VERSION } from './constants';
|
|
104
104
|
const NavigationTracker = ({ onStateChange }) => {
|
|
105
105
|
const navState = useNavigationState(state => state);
|
|
106
106
|
useEffect(() => {
|
|
@@ -114,6 +114,12 @@ const animateNextLayout = () => {
|
|
|
114
114
|
const NetworkInspector = ({ enabled = true, }) => {
|
|
115
115
|
const [isDark, setIsDark] = useState(false);
|
|
116
116
|
const [reduxState, setReduxState] = useState(null);
|
|
117
|
+
// Action timeline + per-reducer last action are kept in component state so the
|
|
118
|
+
// Redux tab re-renders live on every dispatch, independent of the state tree ref.
|
|
119
|
+
const [reduxActionHistory, setReduxActionHistory] = useState([]);
|
|
120
|
+
const [reduxLastActionMap, setReduxLastActionMap] = useState({});
|
|
121
|
+
// Inspector panel height as a percentage of the screen (configurable in Settings).
|
|
122
|
+
const [modalHeightPercent, setModalHeightPercent] = useState(90);
|
|
117
123
|
const [expandedReducers, setExpandedReducers] = useState({});
|
|
118
124
|
const [logs, setLogs] = useState([]);
|
|
119
125
|
const [visible, setVisible] = useState(false);
|
|
@@ -144,6 +150,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
144
150
|
const [showNetworkMenu, setShowNetworkMenu] = useState(false);
|
|
145
151
|
const [showUiMenu, setShowUiMenu] = useState(false);
|
|
146
152
|
const [sortOrder, setSortOrder] = useState('newest');
|
|
153
|
+
// #7 — sort order for the Logs (console) tab
|
|
154
|
+
const [logSortOrder, setLogSortOrder] = useState('newest');
|
|
147
155
|
const [reqExpanded, setReqExpanded] = useState(undefined);
|
|
148
156
|
const [resExpanded, setResExpanded] = useState(undefined);
|
|
149
157
|
const [showReqDiff, setShowReqDiff] = useState(false);
|
|
@@ -323,6 +331,66 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
323
331
|
const badgeAnim = useRef(new Animated.Value(1)).current;
|
|
324
332
|
const activePulseAnim = useRef(new Animated.Value(0.4)).current;
|
|
325
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]);
|
|
326
394
|
useEffect(() => {
|
|
327
395
|
if (Platform.OS === 'android') {
|
|
328
396
|
UIManager.setLayoutAnimationEnabledExperimental?.(true);
|
|
@@ -480,8 +548,14 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
480
548
|
}, 200);
|
|
481
549
|
});
|
|
482
550
|
setReduxState(getReduxState());
|
|
551
|
+
setReduxActionHistory([...getActionHistory()]);
|
|
552
|
+
setReduxLastActionMap({ ...getLastActionForReducer() });
|
|
483
553
|
const unsubscribeRedux = subscribeReduxState(() => {
|
|
554
|
+
// New references each time guarantee the Redux tab updates live, even when
|
|
555
|
+
// the root state object reference is unchanged or auto-refresh is paused.
|
|
484
556
|
setReduxState(getReduxState());
|
|
557
|
+
setReduxActionHistory([...getActionHistory()]);
|
|
558
|
+
setReduxLastActionMap({ ...getLastActionForReducer() });
|
|
485
559
|
});
|
|
486
560
|
return () => {
|
|
487
561
|
unsubscribe();
|
|
@@ -741,8 +815,12 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
741
815
|
result = result.filter(log => log.message.toLowerCase().includes(s) ||
|
|
742
816
|
(log.caller ?? '').toLowerCase().includes(s));
|
|
743
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);
|
|
744
822
|
return result;
|
|
745
|
-
}, [visibleConsoleLogs, logFilters, logSearch]);
|
|
823
|
+
}, [visibleConsoleLogs, logFilters, logSearch, logSortOrder]);
|
|
746
824
|
const filteredWebViewLogs = useMemo(() => {
|
|
747
825
|
let result = webViewLogs;
|
|
748
826
|
if (webViewSearch) {
|
|
@@ -868,6 +946,22 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
868
946
|
]);
|
|
869
947
|
return;
|
|
870
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.
|
|
871
965
|
if (selectedLogs.size > 0) {
|
|
872
966
|
setLogs(prev => prev.filter(l => !selectedLogs.has(l.id)));
|
|
873
967
|
setSelectedLogs(new Set());
|
|
@@ -875,10 +969,22 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
875
969
|
else {
|
|
876
970
|
Alert.alert('Clear Logs', 'Are you sure you want to clear all network logs?', [
|
|
877
971
|
{ text: 'Cancel', style: 'cancel' },
|
|
878
|
-
{ text: 'Clear All', onPress:
|
|
972
|
+
{ text: 'Clear All', onPress: clearNetworkOnly, style: 'destructive' },
|
|
879
973
|
]);
|
|
880
974
|
}
|
|
881
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
|
+
}
|
|
882
988
|
const detailTitle = useMemo(() => {
|
|
883
989
|
if (!selected)
|
|
884
990
|
return '';
|
|
@@ -995,7 +1101,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
995
1101
|
fontSize: 10.5,
|
|
996
1102
|
color: '#FFFFFF',
|
|
997
1103
|
}}>
|
|
998
|
-
|
|
1104
|
+
v{LIB_VERSION}
|
|
999
1105
|
</Text>
|
|
1000
1106
|
</View>
|
|
1001
1107
|
</View>
|
|
@@ -1163,30 +1269,56 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1163
1269
|
width: 38,
|
|
1164
1270
|
height: 22,
|
|
1165
1271
|
borderRadius: 11,
|
|
1166
|
-
backgroundColor:
|
|
1167
|
-
? AppColors.
|
|
1168
|
-
:
|
|
1272
|
+
backgroundColor: isLocked
|
|
1273
|
+
? AppColors.grayBackground
|
|
1274
|
+
: isVisible
|
|
1275
|
+
? AppColors.purple
|
|
1276
|
+
: AppColors.grayBorderSecondary,
|
|
1277
|
+
borderWidth: isLocked ? 1.5 : 0,
|
|
1278
|
+
borderColor: isLocked
|
|
1279
|
+
? AppColors.grayBorderSecondary
|
|
1280
|
+
: 'transparent',
|
|
1281
|
+
borderStyle: isLocked ? 'dashed' : 'solid',
|
|
1169
1282
|
padding: 2,
|
|
1170
1283
|
justifyContent: 'center',
|
|
1171
1284
|
alignItems: isVisible ? 'flex-end' : 'flex-start',
|
|
1285
|
+
opacity: isLocked ? 0.9 : 1,
|
|
1172
1286
|
}}>
|
|
1173
1287
|
<View style={{
|
|
1174
1288
|
width: 18,
|
|
1175
1289
|
height: 18,
|
|
1176
1290
|
borderRadius: 9,
|
|
1177
|
-
backgroundColor:
|
|
1291
|
+
backgroundColor: isLocked
|
|
1292
|
+
? AppColors.grayBorderSecondary
|
|
1293
|
+
: '#FFFFFF',
|
|
1294
|
+
alignItems: 'center',
|
|
1295
|
+
justifyContent: 'center',
|
|
1178
1296
|
shadowColor: '#000',
|
|
1179
|
-
shadowOpacity: 0.15,
|
|
1297
|
+
shadowOpacity: isLocked ? 0 : 0.15,
|
|
1180
1298
|
shadowRadius: 1.5,
|
|
1181
1299
|
shadowOffset: { width: 0, height: 1 },
|
|
1182
|
-
}}
|
|
1300
|
+
}}>
|
|
1301
|
+
{isLocked && (<Svg width={10} height={10} viewBox="0 0 24 24" fill="none">
|
|
1302
|
+
<Path d="M7 10V7a5 5 0 0 1 10 0v3" stroke={AppColors.grayText} strokeWidth="2.2" strokeLinecap="round"/>
|
|
1303
|
+
<Path d="M5 10h14v9a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1z" fill={AppColors.grayText}/>
|
|
1304
|
+
</Svg>)}
|
|
1305
|
+
</View>
|
|
1183
1306
|
</TouchableScale>
|
|
1307
|
+
{isLocked && (<Text style={{
|
|
1308
|
+
fontFamily: AppFonts.interBold,
|
|
1309
|
+
fontSize: 8,
|
|
1310
|
+
color: AppColors.grayTextWeak,
|
|
1311
|
+
letterSpacing: 0.4,
|
|
1312
|
+
marginTop: 3,
|
|
1313
|
+
}}>
|
|
1314
|
+
REQUIRED
|
|
1315
|
+
</Text>)}
|
|
1184
1316
|
</View>
|
|
1185
1317
|
</View>);
|
|
1186
1318
|
})}
|
|
1187
1319
|
</View>
|
|
1188
1320
|
|
|
1189
|
-
{/* Preferences Section */}
|
|
1321
|
+
{/* UI Preferences Section */}
|
|
1190
1322
|
<View style={{ marginTop: 8 }}>
|
|
1191
1323
|
<Text style={{
|
|
1192
1324
|
fontFamily: AppFonts.interBold,
|
|
@@ -1195,7 +1327,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1195
1327
|
letterSpacing: 0.6,
|
|
1196
1328
|
marginBottom: 8,
|
|
1197
1329
|
}}>
|
|
1198
|
-
PREFERENCES
|
|
1330
|
+
UI PREFERENCES
|
|
1199
1331
|
</Text>
|
|
1200
1332
|
<View style={{
|
|
1201
1333
|
backgroundColor: AppColors.primaryLight,
|
|
@@ -1269,6 +1401,86 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1269
1401
|
}}/>
|
|
1270
1402
|
</TouchableScale>
|
|
1271
1403
|
</View>
|
|
1404
|
+
|
|
1405
|
+
{/* Divider */}
|
|
1406
|
+
<View style={{
|
|
1407
|
+
height: 1,
|
|
1408
|
+
backgroundColor: AppColors.dividerColor,
|
|
1409
|
+
}}/>
|
|
1410
|
+
|
|
1411
|
+
{/* Modal Height */}
|
|
1412
|
+
<View style={{
|
|
1413
|
+
paddingVertical: 12,
|
|
1414
|
+
paddingHorizontal: 14,
|
|
1415
|
+
}}>
|
|
1416
|
+
<View style={{
|
|
1417
|
+
flexDirection: 'row',
|
|
1418
|
+
alignItems: 'center',
|
|
1419
|
+
gap: 8,
|
|
1420
|
+
}}>
|
|
1421
|
+
<View style={{
|
|
1422
|
+
width: 20,
|
|
1423
|
+
height: 20,
|
|
1424
|
+
borderRadius: 6,
|
|
1425
|
+
backgroundColor: AppColors.purpleShade50,
|
|
1426
|
+
borderWidth: 1,
|
|
1427
|
+
borderColor: 'rgba(104,75,155,0.2)',
|
|
1428
|
+
alignItems: 'center',
|
|
1429
|
+
justifyContent: 'center',
|
|
1430
|
+
}}>
|
|
1431
|
+
<ScreenIcon color={AppColors.purple} size={11}/>
|
|
1432
|
+
</View>
|
|
1433
|
+
<View style={{ flex: 1 }}>
|
|
1434
|
+
<Text style={{
|
|
1435
|
+
fontFamily: AppFonts.interBold,
|
|
1436
|
+
fontSize: 13,
|
|
1437
|
+
color: AppColors.primaryBlack,
|
|
1438
|
+
}}>
|
|
1439
|
+
Modal Height
|
|
1440
|
+
</Text>
|
|
1441
|
+
<Text style={{
|
|
1442
|
+
fontFamily: AppFonts.interRegular,
|
|
1443
|
+
fontSize: 11,
|
|
1444
|
+
color: AppColors.grayText,
|
|
1445
|
+
marginTop: 1,
|
|
1446
|
+
}}>
|
|
1447
|
+
Height of the inspector panel relative to the screen
|
|
1448
|
+
</Text>
|
|
1449
|
+
</View>
|
|
1450
|
+
</View>
|
|
1451
|
+
|
|
1452
|
+
{/* Segmented picker */}
|
|
1453
|
+
<View style={{
|
|
1454
|
+
flexDirection: 'row',
|
|
1455
|
+
backgroundColor: AppColors.grayBackground,
|
|
1456
|
+
borderRadius: 8,
|
|
1457
|
+
padding: 2.5,
|
|
1458
|
+
marginTop: 10,
|
|
1459
|
+
borderWidth: 1,
|
|
1460
|
+
borderColor: AppColors.dividerColor,
|
|
1461
|
+
}}>
|
|
1462
|
+
{[50, 70, 90, 100].map(opt => {
|
|
1463
|
+
const isActive = modalHeightPercent === opt;
|
|
1464
|
+
return (<TouchableScale key={opt} onPress={() => setModalHeightPercent(opt)} style={{
|
|
1465
|
+
flex: 1,
|
|
1466
|
+
paddingVertical: 6,
|
|
1467
|
+
alignItems: 'center',
|
|
1468
|
+
borderRadius: 6,
|
|
1469
|
+
backgroundColor: isActive
|
|
1470
|
+
? AppColors.purple
|
|
1471
|
+
: 'transparent',
|
|
1472
|
+
}}>
|
|
1473
|
+
<Text style={{
|
|
1474
|
+
fontFamily: AppFonts.interBold,
|
|
1475
|
+
fontSize: 11,
|
|
1476
|
+
color: isActive ? '#FFFFFF' : AppColors.grayText,
|
|
1477
|
+
}}>
|
|
1478
|
+
{opt}%
|
|
1479
|
+
</Text>
|
|
1480
|
+
</TouchableScale>);
|
|
1481
|
+
})}
|
|
1482
|
+
</View>
|
|
1483
|
+
</View>
|
|
1272
1484
|
</View>
|
|
1273
1485
|
</View>
|
|
1274
1486
|
</ScrollView>
|
|
@@ -1403,11 +1615,13 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1403
1615
|
fontSize: 11,
|
|
1404
1616
|
color: isActive ? '#FFFFFF' : AppColors.grayText,
|
|
1405
1617
|
}}>
|
|
1406
|
-
{
|
|
1407
|
-
opt
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1618
|
+
{opts.picker.formatLabel
|
|
1619
|
+
? opts.picker.formatLabel(opt)
|
|
1620
|
+
: typeof opt === 'number' &&
|
|
1621
|
+
opt >= 500 &&
|
|
1622
|
+
settingsPage === 'insights'
|
|
1623
|
+
? `${opt}ms`
|
|
1624
|
+
: opt}
|
|
1411
1625
|
</Text>
|
|
1412
1626
|
</TouchableScale>);
|
|
1413
1627
|
})}
|
|
@@ -1872,7 +2086,187 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1872
2086
|
e.name === 'page_view' ||
|
|
1873
2087
|
e.name === 'firebase_screen_class').length;
|
|
1874
2088
|
const webviewTotal = webViewNavHistory.length;
|
|
2089
|
+
// --- Richer insights metrics ---
|
|
2090
|
+
const slowestTime = durations.length > 0 ? Math.max(...durations) : null;
|
|
2091
|
+
const fastestTime = durations.length > 0 ? Math.min(...durations) : null;
|
|
2092
|
+
const slowCount = durations.filter(d => d >= slowRequestThreshold).length;
|
|
2093
|
+
const status2xx = logs.filter(l => l.status != null && l.status >= 200 && l.status < 300).length;
|
|
2094
|
+
const status3xx = logs.filter(l => l.status != null && l.status >= 300 && l.status < 400).length;
|
|
2095
|
+
const status4xx = logs.filter(l => l.status != null && l.status >= 400 && l.status < 500).length;
|
|
2096
|
+
const status5xx = logs.filter(l => l.status != null && l.status >= 500).length;
|
|
2097
|
+
const totalSignals = apiTotal + logTotal + analyticsTotal + webviewTotal;
|
|
2098
|
+
const totalIssues = apiErrors + logErrors;
|
|
2099
|
+
const activeModules = [
|
|
2100
|
+
tabVisibility.apis,
|
|
2101
|
+
tabVisibility.logs,
|
|
2102
|
+
tabVisibility.analytics,
|
|
2103
|
+
tabVisibility.webview,
|
|
2104
|
+
tabVisibility.redux,
|
|
2105
|
+
].filter(Boolean).length;
|
|
2106
|
+
// Composite health score: success rate penalised by error volume and slow requests.
|
|
2107
|
+
const healthScore = totalSignals === 0
|
|
2108
|
+
? 100
|
|
2109
|
+
: Math.max(0, Math.min(100, Math.round(apiSuccessRate -
|
|
2110
|
+
(logErrors > 0 ? Math.min(15, logErrors * 3) : 0) -
|
|
2111
|
+
(slowCount > 0 ? Math.min(10, slowCount * 2) : 0))));
|
|
2112
|
+
const healthColor = healthScore >= 90
|
|
2113
|
+
? AppColors.greenColor
|
|
2114
|
+
: healthScore >= 70
|
|
2115
|
+
? AppColors.warningIconGold
|
|
2116
|
+
: AppColors.errorColor;
|
|
2117
|
+
const healthLabel = healthScore >= 90
|
|
2118
|
+
? 'Healthy'
|
|
2119
|
+
: healthScore >= 70
|
|
2120
|
+
? 'Needs attention'
|
|
2121
|
+
: 'Degraded';
|
|
1875
2122
|
return (<View style={styles.dashboardContainer}>
|
|
2123
|
+
{/* Overview hero card */}
|
|
2124
|
+
<View style={{
|
|
2125
|
+
backgroundColor: AppColors.primaryLight,
|
|
2126
|
+
borderRadius: 14,
|
|
2127
|
+
borderWidth: 1,
|
|
2128
|
+
borderColor: AppColors.grayBorderSecondary,
|
|
2129
|
+
padding: 16,
|
|
2130
|
+
marginBottom: 12,
|
|
2131
|
+
}}>
|
|
2132
|
+
<View style={{
|
|
2133
|
+
flexDirection: 'row',
|
|
2134
|
+
alignItems: 'center',
|
|
2135
|
+
gap: 14,
|
|
2136
|
+
}}>
|
|
2137
|
+
{/* Health ring stand-in */}
|
|
2138
|
+
<View style={{
|
|
2139
|
+
width: 64,
|
|
2140
|
+
height: 64,
|
|
2141
|
+
borderRadius: 32,
|
|
2142
|
+
borderWidth: 4,
|
|
2143
|
+
borderColor: healthColor,
|
|
2144
|
+
alignItems: 'center',
|
|
2145
|
+
justifyContent: 'center',
|
|
2146
|
+
backgroundColor: AppColors.purpleShade50,
|
|
2147
|
+
}}>
|
|
2148
|
+
<Text style={{
|
|
2149
|
+
fontFamily: AppFonts.interBold,
|
|
2150
|
+
fontSize: 18,
|
|
2151
|
+
color: healthColor,
|
|
2152
|
+
}}>
|
|
2153
|
+
{healthScore}
|
|
2154
|
+
</Text>
|
|
2155
|
+
<Text style={{
|
|
2156
|
+
fontFamily: AppFonts.interMedium,
|
|
2157
|
+
fontSize: 7.5,
|
|
2158
|
+
color: AppColors.grayTextWeak,
|
|
2159
|
+
letterSpacing: 0.4,
|
|
2160
|
+
}}>
|
|
2161
|
+
HEALTH
|
|
2162
|
+
</Text>
|
|
2163
|
+
</View>
|
|
2164
|
+
<View style={{ flex: 1 }}>
|
|
2165
|
+
<Text style={{
|
|
2166
|
+
fontFamily: AppFonts.interBold,
|
|
2167
|
+
fontSize: 15,
|
|
2168
|
+
color: AppColors.primaryBlack,
|
|
2169
|
+
}}>
|
|
2170
|
+
Session Overview
|
|
2171
|
+
</Text>
|
|
2172
|
+
<View style={{
|
|
2173
|
+
flexDirection: 'row',
|
|
2174
|
+
alignItems: 'center',
|
|
2175
|
+
gap: 6,
|
|
2176
|
+
marginTop: 3,
|
|
2177
|
+
}}>
|
|
2178
|
+
<View style={{
|
|
2179
|
+
width: 7,
|
|
2180
|
+
height: 7,
|
|
2181
|
+
borderRadius: 3.5,
|
|
2182
|
+
backgroundColor: healthColor,
|
|
2183
|
+
}}/>
|
|
2184
|
+
<Text style={{
|
|
2185
|
+
fontFamily: AppFonts.interMedium,
|
|
2186
|
+
fontSize: 11.5,
|
|
2187
|
+
color: healthColor,
|
|
2188
|
+
}}>
|
|
2189
|
+
{healthLabel}
|
|
2190
|
+
</Text>
|
|
2191
|
+
<Text style={{
|
|
2192
|
+
fontFamily: AppFonts.interRegular,
|
|
2193
|
+
fontSize: 11.5,
|
|
2194
|
+
color: AppColors.grayTextWeak,
|
|
2195
|
+
}}>
|
|
2196
|
+
• {activeModules} modules active
|
|
2197
|
+
</Text>
|
|
2198
|
+
</View>
|
|
2199
|
+
</View>
|
|
2200
|
+
</View>
|
|
2201
|
+
|
|
2202
|
+
{/* Quick totals strip */}
|
|
2203
|
+
<View style={{
|
|
2204
|
+
flexDirection: 'row',
|
|
2205
|
+
marginTop: 14,
|
|
2206
|
+
borderTopWidth: 1,
|
|
2207
|
+
borderTopColor: AppColors.dividerColor,
|
|
2208
|
+
paddingTop: 12,
|
|
2209
|
+
}}>
|
|
2210
|
+
<View style={{ flex: 1, alignItems: 'center' }}>
|
|
2211
|
+
<Text style={{
|
|
2212
|
+
fontFamily: AppFonts.interBold,
|
|
2213
|
+
fontSize: 16,
|
|
2214
|
+
color: AppColors.primaryBlack,
|
|
2215
|
+
}}>
|
|
2216
|
+
{totalSignals}
|
|
2217
|
+
</Text>
|
|
2218
|
+
<Text style={{
|
|
2219
|
+
fontFamily: AppFonts.interRegular,
|
|
2220
|
+
fontSize: 10,
|
|
2221
|
+
color: AppColors.grayTextWeak,
|
|
2222
|
+
marginTop: 1,
|
|
2223
|
+
}}>
|
|
2224
|
+
Signals
|
|
2225
|
+
</Text>
|
|
2226
|
+
</View>
|
|
2227
|
+
<View style={{ width: 1, backgroundColor: AppColors.dividerColor }}/>
|
|
2228
|
+
<View style={{ flex: 1, alignItems: 'center' }}>
|
|
2229
|
+
<Text style={{
|
|
2230
|
+
fontFamily: AppFonts.interBold,
|
|
2231
|
+
fontSize: 16,
|
|
2232
|
+
color: totalIssues > 0
|
|
2233
|
+
? AppColors.errorColor
|
|
2234
|
+
: AppColors.primaryBlack,
|
|
2235
|
+
}}>
|
|
2236
|
+
{totalIssues}
|
|
2237
|
+
</Text>
|
|
2238
|
+
<Text style={{
|
|
2239
|
+
fontFamily: AppFonts.interRegular,
|
|
2240
|
+
fontSize: 10,
|
|
2241
|
+
color: AppColors.grayTextWeak,
|
|
2242
|
+
marginTop: 1,
|
|
2243
|
+
}}>
|
|
2244
|
+
Issues
|
|
2245
|
+
</Text>
|
|
2246
|
+
</View>
|
|
2247
|
+
<View style={{ width: 1, backgroundColor: AppColors.dividerColor }}/>
|
|
2248
|
+
<View style={{ flex: 1, alignItems: 'center' }}>
|
|
2249
|
+
<Text style={{
|
|
2250
|
+
fontFamily: AppFonts.interBold,
|
|
2251
|
+
fontSize: 16,
|
|
2252
|
+
color: slowCount > 0
|
|
2253
|
+
? AppColors.warningIconGold
|
|
2254
|
+
: AppColors.primaryBlack,
|
|
2255
|
+
}}>
|
|
2256
|
+
{slowCount}
|
|
2257
|
+
</Text>
|
|
2258
|
+
<Text style={{
|
|
2259
|
+
fontFamily: AppFonts.interRegular,
|
|
2260
|
+
fontSize: 10,
|
|
2261
|
+
color: AppColors.grayTextWeak,
|
|
2262
|
+
marginTop: 1,
|
|
2263
|
+
}}>
|
|
2264
|
+
Slow ({slowRequestThreshold}ms+)
|
|
2265
|
+
</Text>
|
|
2266
|
+
</View>
|
|
2267
|
+
</View>
|
|
2268
|
+
</View>
|
|
2269
|
+
|
|
1876
2270
|
{/* Module 1: APIs */}
|
|
1877
2271
|
{tabVisibility.apis && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('apis')}>
|
|
1878
2272
|
<View style={styles.dashboardModuleHeader}>
|
|
@@ -1912,9 +2306,75 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1912
2306
|
<Text style={styles.dashboardGridLbl}>Avg Latency</Text>
|
|
1913
2307
|
</View>
|
|
1914
2308
|
</View>
|
|
1915
|
-
</TouchableScale>)}
|
|
1916
2309
|
|
|
1917
|
-
|
|
2310
|
+
{/* Status-class breakdown + latency range */}
|
|
2311
|
+
<View style={{
|
|
2312
|
+
marginTop: 10,
|
|
2313
|
+
paddingTop: 10,
|
|
2314
|
+
borderTopWidth: 1,
|
|
2315
|
+
borderTopColor: AppColors.dividerColor,
|
|
2316
|
+
flexDirection: 'row',
|
|
2317
|
+
alignItems: 'center',
|
|
2318
|
+
flexWrap: 'wrap',
|
|
2319
|
+
gap: 6,
|
|
2320
|
+
}}>
|
|
2321
|
+
{[
|
|
2322
|
+
{ label: '2xx', value: status2xx, color: AppColors.greenColor },
|
|
2323
|
+
{ label: '3xx', value: status3xx, color: AppColors.skyBlue },
|
|
2324
|
+
{
|
|
2325
|
+
label: '4xx',
|
|
2326
|
+
value: status4xx,
|
|
2327
|
+
color: AppColors.warningIconGold,
|
|
2328
|
+
},
|
|
2329
|
+
{ label: '5xx', value: status5xx, color: AppColors.errorColor },
|
|
2330
|
+
].map(s => (<View key={s.label} style={{
|
|
2331
|
+
flexDirection: 'row',
|
|
2332
|
+
alignItems: 'center',
|
|
2333
|
+
gap: 4,
|
|
2334
|
+
backgroundColor: AppColors.grayBackground,
|
|
2335
|
+
borderRadius: 6,
|
|
2336
|
+
borderWidth: 1,
|
|
2337
|
+
borderColor: AppColors.dividerColor,
|
|
2338
|
+
paddingHorizontal: 7,
|
|
2339
|
+
paddingVertical: 3,
|
|
2340
|
+
}}>
|
|
2341
|
+
<View style={{
|
|
2342
|
+
width: 6,
|
|
2343
|
+
height: 6,
|
|
2344
|
+
borderRadius: 3,
|
|
2345
|
+
backgroundColor: s.color,
|
|
2346
|
+
}}/>
|
|
2347
|
+
<Text style={{
|
|
2348
|
+
fontFamily: AppFonts.interBold,
|
|
2349
|
+
fontSize: 10,
|
|
2350
|
+
color: AppColors.grayTextStrong,
|
|
2351
|
+
}}>
|
|
2352
|
+
{s.label} {s.value}
|
|
2353
|
+
</Text>
|
|
2354
|
+
</View>))}
|
|
2355
|
+
{slowestTime != null && (<View style={{
|
|
2356
|
+
marginLeft: 'auto',
|
|
2357
|
+
flexDirection: 'row',
|
|
2358
|
+
alignItems: 'center',
|
|
2359
|
+
gap: 4,
|
|
2360
|
+
}}>
|
|
2361
|
+
<Text style={{
|
|
2362
|
+
fontFamily: AppFonts.interRegular,
|
|
2363
|
+
fontSize: 10,
|
|
2364
|
+
color: AppColors.grayTextWeak,
|
|
2365
|
+
}}>
|
|
2366
|
+
Range
|
|
2367
|
+
</Text>
|
|
2368
|
+
<Text style={{
|
|
2369
|
+
fontFamily: AppFonts.interBold,
|
|
2370
|
+
fontSize: 10,
|
|
2371
|
+
color: AppColors.grayTextStrong,
|
|
2372
|
+
}}>
|
|
2373
|
+
{fastestTime}–{slowestTime}ms
|
|
2374
|
+
</Text>
|
|
2375
|
+
</View>)}
|
|
2376
|
+
</View>
|
|
2377
|
+
</TouchableScale>)}
|
|
1918
2378
|
{tabVisibility.logs && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('logs')}>
|
|
1919
2379
|
<View style={styles.dashboardModuleHeader}>
|
|
1920
2380
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
@@ -2118,54 +2578,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2118
2578
|
<Text style={styles.emptySub}>Connected store state is empty.</Text>
|
|
2119
2579
|
</View>);
|
|
2120
2580
|
}
|
|
2121
|
-
// Build hierarchical tree: Store -> Reducers -> Action -> Data
|
|
2122
|
-
|
|
2123
|
-
const
|
|
2581
|
+
// Build hierarchical tree: Store -> Reducers -> Action -> Data.
|
|
2582
|
+
// These come from component state (refreshed on every dispatch) so the view stays live.
|
|
2583
|
+
const lastActionMap = reduxLastActionMap;
|
|
2584
|
+
const actionHistory = reduxActionHistory;
|
|
2124
2585
|
return (<ScrollView style={styles.detailScroll} contentContainerStyle={{ paddingBottom: 24 }}>
|
|
2125
|
-
{/* Top Summary Card */}
|
|
2126
|
-
<View style={{
|
|
2127
|
-
backgroundColor: AppColors.primaryLight,
|
|
2128
|
-
borderRadius: 12,
|
|
2129
|
-
borderWidth: 1,
|
|
2130
|
-
borderColor: AppColors.grayBorderSecondary,
|
|
2131
|
-
padding: 14,
|
|
2132
|
-
marginHorizontal: 16,
|
|
2133
|
-
marginTop: 12,
|
|
2134
|
-
marginBottom: 12,
|
|
2135
|
-
flexDirection: 'row',
|
|
2136
|
-
alignItems: 'center',
|
|
2137
|
-
gap: 12,
|
|
2138
|
-
}}>
|
|
2139
|
-
<View style={{
|
|
2140
|
-
width: 44,
|
|
2141
|
-
height: 44,
|
|
2142
|
-
borderRadius: 10,
|
|
2143
|
-
backgroundColor: AppColors.purpleShade50,
|
|
2144
|
-
alignItems: 'center',
|
|
2145
|
-
justifyContent: 'center',
|
|
2146
|
-
}}>
|
|
2147
|
-
<TerminalIcon color={AppColors.purple} size={20}/>
|
|
2148
|
-
</View>
|
|
2149
|
-
<View style={{ flex: 1 }}>
|
|
2150
|
-
<Text style={{
|
|
2151
|
-
fontFamily: AppFonts.interBold,
|
|
2152
|
-
fontSize: 13,
|
|
2153
|
-
color: AppColors.primaryBlack,
|
|
2154
|
-
}}>
|
|
2155
|
-
Redux Store Snapshot
|
|
2156
|
-
</Text>
|
|
2157
|
-
<Text style={{
|
|
2158
|
-
fontFamily: AppFonts.interRegular,
|
|
2159
|
-
fontSize: 11,
|
|
2160
|
-
color: AppColors.grayText,
|
|
2161
|
-
marginTop: 2,
|
|
2162
|
-
}}>
|
|
2163
|
-
Total size: {getSize(reduxState)} • {reducerKeys.length} Reducers
|
|
2164
|
-
</Text>
|
|
2165
|
-
</View>
|
|
2166
|
-
<CopyButton value={() => reduxState} label="Overall Store"/>
|
|
2167
|
-
</View>
|
|
2168
|
-
|
|
2169
2586
|
{/* Tab View Selection Segments */}
|
|
2170
2587
|
<View style={{
|
|
2171
2588
|
flexDirection: 'row',
|
|
@@ -2173,6 +2590,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2173
2590
|
borderRadius: 10,
|
|
2174
2591
|
padding: 3,
|
|
2175
2592
|
marginHorizontal: 16,
|
|
2593
|
+
marginTop: 12,
|
|
2176
2594
|
marginBottom: 12,
|
|
2177
2595
|
borderWidth: 1,
|
|
2178
2596
|
borderColor: AppColors.dividerColor,
|
|
@@ -2190,15 +2608,46 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2190
2608
|
? AppColors.purple
|
|
2191
2609
|
: 'transparent',
|
|
2192
2610
|
}}>
|
|
2193
|
-
<
|
|
2611
|
+
<View style={{
|
|
2612
|
+
flexDirection: 'row',
|
|
2613
|
+
alignItems: 'center',
|
|
2614
|
+
justifyContent: 'center',
|
|
2615
|
+
gap: 6,
|
|
2616
|
+
}}>
|
|
2617
|
+
<ReduxTimelineIcon color={reduxActiveSubTab === 'timeline'
|
|
2618
|
+
? '#FFFFFF'
|
|
2619
|
+
: AppColors.grayText} size={13}/>
|
|
2620
|
+
<Text style={{
|
|
2194
2621
|
fontFamily: AppFonts.interBold,
|
|
2195
2622
|
fontSize: 11,
|
|
2196
2623
|
color: reduxActiveSubTab === 'timeline'
|
|
2197
2624
|
? '#FFFFFF'
|
|
2198
2625
|
: AppColors.grayText,
|
|
2199
2626
|
}}>
|
|
2200
|
-
|
|
2201
|
-
|
|
2627
|
+
Action Timeline
|
|
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>
|
|
2650
|
+
</View>
|
|
2202
2651
|
</TouchableOpacity>
|
|
2203
2652
|
<TouchableOpacity onPress={() => {
|
|
2204
2653
|
animateNextLayout();
|
|
@@ -2211,13 +2660,44 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2211
2660
|
borderRadius: 8,
|
|
2212
2661
|
backgroundColor: reduxActiveSubTab === 'tree' ? AppColors.purple : 'transparent',
|
|
2213
2662
|
}}>
|
|
2214
|
-
<
|
|
2663
|
+
<View style={{
|
|
2664
|
+
flexDirection: 'row',
|
|
2665
|
+
alignItems: 'center',
|
|
2666
|
+
justifyContent: 'center',
|
|
2667
|
+
gap: 6,
|
|
2668
|
+
}}>
|
|
2669
|
+
<ReduxTreeIcon color={reduxActiveSubTab === 'tree' ? '#FFFFFF' : AppColors.grayText} size={13}/>
|
|
2670
|
+
<Text style={{
|
|
2215
2671
|
fontFamily: AppFonts.interBold,
|
|
2216
2672
|
fontSize: 11,
|
|
2217
|
-
color: reduxActiveSubTab === 'tree'
|
|
2673
|
+
color: reduxActiveSubTab === 'tree'
|
|
2674
|
+
? '#FFFFFF'
|
|
2675
|
+
: AppColors.grayText,
|
|
2218
2676
|
}}>
|
|
2219
|
-
|
|
2220
|
-
|
|
2677
|
+
Store Tree
|
|
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>
|
|
2700
|
+
</View>
|
|
2221
2701
|
</TouchableOpacity>
|
|
2222
2702
|
</View>
|
|
2223
2703
|
|
|
@@ -2263,27 +2743,36 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2263
2743
|
};
|
|
2264
2744
|
return (<>
|
|
2265
2745
|
{hasNavigationContext && (<NavigationTracker onStateChange={setNavState}/>)}
|
|
2266
|
-
<
|
|
2267
|
-
<
|
|
2268
|
-
|
|
2269
|
-
|
|
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={[
|
|
2270
2755
|
styles.fabBadge,
|
|
2271
2756
|
hasErrors ? styles.fabBadgeError : styles.fabBadgeNormal,
|
|
2272
2757
|
{ transform: [{ scale: badgeAnim }] },
|
|
2273
2758
|
]}>
|
|
2274
|
-
|
|
2275
|
-
|
|
2759
|
+
<Text style={styles.fabBadgeText}>
|
|
2760
|
+
{logs.length + analyticsEvents.length > 99
|
|
2276
2761
|
? '99+'
|
|
2277
2762
|
: logs.length + analyticsEvents.length}
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2763
|
+
</Text>
|
|
2764
|
+
</Animated.View>)}
|
|
2765
|
+
</TouchableScale>
|
|
2766
|
+
</Animated.View>
|
|
2281
2767
|
|
|
2282
2768
|
<Modal visible={visible} animationType="slide" transparent>
|
|
2283
2769
|
{visible && (<ErrorBoundary onClose={closeModal}>
|
|
2284
2770
|
<View style={styles.modalBackdrop}>
|
|
2285
2771
|
<Pressable style={styles.modalBackdropPressable} onPress={closeModal}/>
|
|
2286
|
-
<View style={
|
|
2772
|
+
<View style={[
|
|
2773
|
+
styles.modalContentCard,
|
|
2774
|
+
{ height: `${modalHeightPercent}%` },
|
|
2775
|
+
]}>
|
|
2287
2776
|
<StatusBar translucent backgroundColor="transparent" barStyle="light-content"/>
|
|
2288
2777
|
|
|
2289
2778
|
<LinearGradient colors={[AppColors.purple, '#6B4EFF']} style={styles.headerGradient}>
|
|
@@ -2304,10 +2793,27 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2304
2793
|
setSelectedEvent(null);
|
|
2305
2794
|
});
|
|
2306
2795
|
}} hitSlop={15} style={[
|
|
2307
|
-
|
|
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
|
+
},
|
|
2308
2806
|
selected == null &&
|
|
2309
2807
|
selectedEvent == null && { display: 'none' },
|
|
2310
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
|
+
}}/>
|
|
2311
2817
|
<WhiteBackNavigation />
|
|
2312
2818
|
</TouchableScale>
|
|
2313
2819
|
|
|
@@ -2318,8 +2824,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2318
2824
|
flex: 1,
|
|
2319
2825
|
}}>
|
|
2320
2826
|
<View style={{
|
|
2321
|
-
width:
|
|
2322
|
-
height:
|
|
2827
|
+
width: 50,
|
|
2828
|
+
height: 50,
|
|
2323
2829
|
borderRadius: 10,
|
|
2324
2830
|
backgroundColor: 'rgba(255,255,255,0.13)',
|
|
2325
2831
|
borderWidth: 1.5,
|
|
@@ -2331,37 +2837,92 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2331
2837
|
shadowRadius: 4,
|
|
2332
2838
|
shadowOffset: { width: 0, height: 2 },
|
|
2333
2839
|
}}>
|
|
2334
|
-
<BrandSquareIcon size={
|
|
2840
|
+
<BrandSquareIcon size={45}/>
|
|
2335
2841
|
</View>
|
|
2336
2842
|
<View style={{ gap: 3 }}>
|
|
2337
|
-
<Text style={[
|
|
2338
|
-
styles.headerTitle,
|
|
2339
|
-
{ fontSize: 17, letterSpacing: 0.2 },
|
|
2340
|
-
]}>
|
|
2843
|
+
<Text style={[styles.headerTitle]}>
|
|
2341
2844
|
RN InApp Inspector
|
|
2342
2845
|
</Text>
|
|
2343
2846
|
<View style={{
|
|
2344
2847
|
flexDirection: 'row',
|
|
2345
2848
|
alignItems: 'center',
|
|
2346
|
-
gap:
|
|
2849
|
+
gap: 6,
|
|
2347
2850
|
}}>
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2851
|
+
{/* OS chip */}
|
|
2852
|
+
<View style={{
|
|
2853
|
+
flexDirection: 'row',
|
|
2854
|
+
alignItems: 'center',
|
|
2855
|
+
borderRadius: 6,
|
|
2856
|
+
overflow: 'hidden',
|
|
2857
|
+
borderWidth: 1,
|
|
2858
|
+
borderColor: 'rgba(255,255,255,0.18)',
|
|
2859
|
+
}}>
|
|
2860
|
+
<View style={{
|
|
2861
|
+
paddingHorizontal: 5,
|
|
2862
|
+
paddingVertical: 2,
|
|
2863
|
+
backgroundColor: 'rgba(255,255,255,0.28)',
|
|
2864
|
+
}}>
|
|
2865
|
+
<Text style={{
|
|
2866
|
+
fontFamily: AppFonts.interBold,
|
|
2867
|
+
fontSize: 9,
|
|
2868
|
+
color: '#FFFFFF',
|
|
2869
|
+
letterSpacing: 0.3,
|
|
2870
|
+
}}>
|
|
2871
|
+
{Platform.OS === 'ios' ? 'iOS' : 'Android'}
|
|
2872
|
+
</Text>
|
|
2873
|
+
</View>
|
|
2874
|
+
<View style={{
|
|
2875
|
+
paddingHorizontal: 5,
|
|
2876
|
+
paddingVertical: 2,
|
|
2877
|
+
backgroundColor: 'rgba(255,255,255,0.12)',
|
|
2878
|
+
}}>
|
|
2879
|
+
<Text style={{
|
|
2356
2880
|
fontFamily: AppFonts.interMedium,
|
|
2357
|
-
fontSize:
|
|
2358
|
-
color: 'rgba(255,255,255,0.
|
|
2881
|
+
fontSize: 9.5,
|
|
2882
|
+
color: 'rgba(255,255,255,0.92)',
|
|
2883
|
+
}}>
|
|
2884
|
+
{String(Platform.Version)}
|
|
2885
|
+
</Text>
|
|
2886
|
+
</View>
|
|
2887
|
+
</View>
|
|
2888
|
+
|
|
2889
|
+
{/* npm chip */}
|
|
2890
|
+
<View style={{
|
|
2891
|
+
flexDirection: 'row',
|
|
2892
|
+
alignItems: 'center',
|
|
2893
|
+
borderRadius: 6,
|
|
2894
|
+
overflow: 'hidden',
|
|
2895
|
+
borderWidth: 1,
|
|
2896
|
+
borderColor: 'rgba(255,255,255,0.18)',
|
|
2897
|
+
}}>
|
|
2898
|
+
<View style={{
|
|
2899
|
+
paddingHorizontal: 5,
|
|
2900
|
+
paddingVertical: 2,
|
|
2901
|
+
backgroundColor: 'rgba(255,255,255,0.28)',
|
|
2902
|
+
}}>
|
|
2903
|
+
<Text style={{
|
|
2904
|
+
fontFamily: AppFonts.interBold,
|
|
2905
|
+
fontSize: 9,
|
|
2906
|
+
color: '#FFFFFF',
|
|
2359
2907
|
letterSpacing: 0.3,
|
|
2360
2908
|
}}>
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2909
|
+
npm
|
|
2910
|
+
</Text>
|
|
2911
|
+
</View>
|
|
2912
|
+
<View style={{
|
|
2913
|
+
paddingHorizontal: 5,
|
|
2914
|
+
paddingVertical: 2,
|
|
2915
|
+
backgroundColor: 'rgba(255,255,255,0.12)',
|
|
2916
|
+
}}>
|
|
2917
|
+
<Text style={{
|
|
2918
|
+
fontFamily: AppFonts.interMedium,
|
|
2919
|
+
fontSize: 9.5,
|
|
2920
|
+
color: 'rgba(255,255,255,0.92)',
|
|
2921
|
+
}}>
|
|
2922
|
+
v{LIB_VERSION}
|
|
2923
|
+
</Text>
|
|
2924
|
+
</View>
|
|
2925
|
+
</View>
|
|
2365
2926
|
</View>
|
|
2366
2927
|
</View>
|
|
2367
2928
|
</View>) : null}
|
|
@@ -2386,21 +2947,48 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2386
2947
|
</Text>
|
|
2387
2948
|
</View>
|
|
2388
2949
|
<View style={styles.headerDetailSubRow}>
|
|
2389
|
-
<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={[
|
|
2390
2962
|
styles.headerStatusDot,
|
|
2391
2963
|
{
|
|
2392
2964
|
backgroundColor: getStatusColor(selected.status),
|
|
2393
2965
|
},
|
|
2394
2966
|
]}/>
|
|
2395
|
-
|
|
2396
|
-
|
|
2967
|
+
<Text style={[
|
|
2968
|
+
styles.headerSubTitle,
|
|
2969
|
+
{ fontFamily: AppFonts.interBold },
|
|
2970
|
+
]}>
|
|
2971
|
+
{selected.status === 0
|
|
2397
2972
|
? 'Failed'
|
|
2398
|
-
: selected.status ?? 'Pending'}
|
|
2399
|
-
|
|
2400
|
-
|
|
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
|
|
2401
2988
|
? `${selected.duration}ms`
|
|
2402
|
-
: '
|
|
2403
|
-
|
|
2989
|
+
: '—'}
|
|
2990
|
+
</Text>
|
|
2991
|
+
</View>
|
|
2404
2992
|
</View>
|
|
2405
2993
|
</View>) : selectedEvent != null ? (<View style={styles.headerDetailCenter}>
|
|
2406
2994
|
<View style={styles.headerDetailRow}>
|
|
@@ -2443,7 +3031,50 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2443
3031
|
</View>) : null}
|
|
2444
3032
|
</View>
|
|
2445
3033
|
|
|
2446
|
-
<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
|
+
|
|
2447
3078
|
{selected == null && selectedEvent == null && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={[
|
|
2448
3079
|
styles.closeButtonSquare,
|
|
2449
3080
|
{
|
|
@@ -2778,50 +3409,53 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2778
3409
|
filteredAnalyticsEvents.length === 0 && {
|
|
2779
3410
|
flexGrow: 1,
|
|
2780
3411
|
},
|
|
2781
|
-
]} keyboardShouldPersistTaps="handled"/>)) : activeTab === 'apis' && selected == null ? (<
|
|
2782
|
-
|
|
2783
|
-
<View style={styles.
|
|
2784
|
-
<
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
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>
|
|
2790
3422
|
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
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>
|
|
2800
3432
|
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
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>
|
|
2804
3436
|
|
|
2805
|
-
|
|
3437
|
+
<TouchableScale style={[
|
|
2806
3438
|
styles.toolbarBtn,
|
|
2807
3439
|
filtersAccordion.isOpen &&
|
|
2808
3440
|
styles.toolbarBtnActive,
|
|
2809
3441
|
]} onPress={filtersAccordion.toggleOpen} hitSlop={10}>
|
|
2810
|
-
|
|
3442
|
+
<FilterIcon color={filtersAccordion.isOpen
|
|
2811
3443
|
? AppColors.purple
|
|
2812
3444
|
: AppColors.grayTextStrong} size={18}/>
|
|
2813
|
-
|
|
3445
|
+
</TouchableScale>
|
|
3446
|
+
</View>
|
|
2814
3447
|
</View>
|
|
2815
|
-
</View>
|
|
2816
3448
|
|
|
2817
|
-
|
|
3449
|
+
<Animated.View style={[
|
|
2818
3450
|
filtersAccordion.bodyStyle,
|
|
2819
3451
|
{ overflow: 'hidden' },
|
|
2820
3452
|
]}>
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
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 => {
|
|
2825
3459
|
const isAll = filter === 'ALL';
|
|
2826
3460
|
const active = isAll
|
|
2827
3461
|
? statusFilters.size === 0
|
|
@@ -2840,38 +3474,38 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2840
3474
|
});
|
|
2841
3475
|
}
|
|
2842
3476
|
}} hitSlop={10}>
|
|
2843
|
-
|
|
3477
|
+
{active ? (<View style={[
|
|
2844
3478
|
styles.statusFilterChip,
|
|
2845
3479
|
styles.statusFilterActive,
|
|
2846
3480
|
{ overflow: 'hidden' },
|
|
2847
3481
|
]}>
|
|
2848
|
-
|
|
3482
|
+
<LinearGradient colors={[
|
|
2849
3483
|
AppColors.purpleShade50,
|
|
2850
3484
|
'#EAE5FF',
|
|
2851
3485
|
]} style={StyleSheet.absoluteFill} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }}/>
|
|
2852
|
-
|
|
3486
|
+
<Text style={[
|
|
2853
3487
|
styles.statusFilterText,
|
|
2854
3488
|
{ color: AppColors.purple },
|
|
2855
3489
|
]}>
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
3490
|
+
{filter}
|
|
3491
|
+
</Text>
|
|
3492
|
+
</View>) : (<View style={styles.statusFilterChip}>
|
|
3493
|
+
<Text style={styles.statusFilterText}>
|
|
3494
|
+
{filter}
|
|
3495
|
+
</Text>
|
|
3496
|
+
</View>)}
|
|
3497
|
+
</TouchableScale>);
|
|
2864
3498
|
})}
|
|
2865
|
-
|
|
3499
|
+
</ScrollView>
|
|
2866
3500
|
|
|
2867
|
-
|
|
3501
|
+
<Text style={[
|
|
2868
3502
|
styles.filtersHeading,
|
|
2869
3503
|
{ marginTop: 16 },
|
|
2870
3504
|
]}>
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
3505
|
+
METHOD
|
|
3506
|
+
</Text>
|
|
3507
|
+
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.statusRowContent}>
|
|
3508
|
+
{availableMethods.map(filter => {
|
|
2875
3509
|
const isAll = filter === 'ALL';
|
|
2876
3510
|
const active = isAll
|
|
2877
3511
|
? methodFilters.size === 0
|
|
@@ -2890,43 +3524,55 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2890
3524
|
});
|
|
2891
3525
|
}
|
|
2892
3526
|
}} hitSlop={10}>
|
|
2893
|
-
|
|
3527
|
+
{active ? (<View style={[
|
|
2894
3528
|
styles.statusFilterChip,
|
|
2895
3529
|
styles.statusFilterActive,
|
|
2896
3530
|
{ overflow: 'hidden' },
|
|
2897
3531
|
]}>
|
|
2898
|
-
|
|
3532
|
+
<LinearGradient colors={[
|
|
2899
3533
|
AppColors.purpleShade50,
|
|
2900
3534
|
'#EAE5FF',
|
|
2901
3535
|
]} style={StyleSheet.absoluteFill} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }}/>
|
|
2902
|
-
|
|
3536
|
+
<Text style={[
|
|
2903
3537
|
styles.statusFilterText,
|
|
2904
3538
|
{ color: AppColors.purple },
|
|
2905
3539
|
]}>
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
3540
|
+
{filter}
|
|
3541
|
+
</Text>
|
|
3542
|
+
</View>) : (<View style={styles.statusFilterChip}>
|
|
3543
|
+
<Text style={styles.statusFilterText}>
|
|
3544
|
+
{filter}
|
|
3545
|
+
</Text>
|
|
3546
|
+
</View>)}
|
|
3547
|
+
</TouchableScale>);
|
|
2914
3548
|
})}
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
3549
|
+
</ScrollView>
|
|
3550
|
+
</View>
|
|
3551
|
+
</Animated.View>
|
|
2918
3552
|
|
|
2919
|
-
|
|
3553
|
+
{(search ||
|
|
2920
3554
|
statusFilters.size > 0 ||
|
|
2921
3555
|
methodFilters.size > 0) && (<Text style={styles.resultCount}>
|
|
2922
|
-
|
|
3556
|
+
{filteredLogs.length === logs.length
|
|
2923
3557
|
? `${logs.length} requests`
|
|
2924
3558
|
: `${filteredLogs.length} of ${logs.length} filtered requests`}
|
|
2925
|
-
|
|
2926
|
-
|
|
3559
|
+
</Text>)}
|
|
3560
|
+
</View>} ListEmptyComponent={<EmptyState isSearch={search.length > 0 || statusFilters.size > 0}/>} contentContainerStyle={[
|
|
2927
3561
|
styles.listContent,
|
|
2928
3562
|
filteredLogs.length === 0 && { flexGrow: 1 },
|
|
2929
|
-
]} 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 }}>
|
|
2930
3576
|
<View style={{
|
|
2931
3577
|
backgroundColor: '#FFFFFF',
|
|
2932
3578
|
borderBottomWidth: 1,
|
|
@@ -2946,6 +3592,9 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2946
3592
|
</View>
|
|
2947
3593
|
|
|
2948
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>
|
|
2949
3598
|
<TouchableScale style={styles.toolbarBtn} onPress={handleDelete} hitSlop={10}>
|
|
2950
3599
|
<TrashIcon color={AppColors.grayTextStrong} size={18}/>
|
|
2951
3600
|
</TouchableScale>
|
|
@@ -4185,7 +4834,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
4185
4834
|
if (!resExpanded && !showResDiff)
|
|
4186
4835
|
setResExpanded(true);
|
|
4187
4836
|
}}/>
|
|
4188
|
-
{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/>)}
|
|
4189
4838
|
</View>
|
|
4190
4839
|
</>)}
|
|
4191
4840
|
</ScrollView>
|