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.
@@ -153,6 +153,12 @@ const animateNextLayout = () => {
153
153
  const NetworkInspector = ({ enabled = true, }) => {
154
154
  const [isDark, setIsDark] = (0, react_1.useState)(false);
155
155
  const [reduxState, setReduxState] = (0, react_1.useState)(null);
156
+ // Action timeline + per-reducer last action are kept in component state so the
157
+ // Redux tab re-renders live on every dispatch, independent of the state tree ref.
158
+ const [reduxActionHistory, setReduxActionHistory] = (0, react_1.useState)([]);
159
+ const [reduxLastActionMap, setReduxLastActionMap] = (0, react_1.useState)({});
160
+ // Inspector panel height as a percentage of the screen (configurable in Settings).
161
+ const [modalHeightPercent, setModalHeightPercent] = (0, react_1.useState)(90);
156
162
  const [expandedReducers, setExpandedReducers] = (0, react_1.useState)({});
157
163
  const [logs, setLogs] = (0, react_1.useState)([]);
158
164
  const [visible, setVisible] = (0, react_1.useState)(false);
@@ -183,6 +189,8 @@ const NetworkInspector = ({ enabled = true, }) => {
183
189
  const [showNetworkMenu, setShowNetworkMenu] = (0, react_1.useState)(false);
184
190
  const [showUiMenu, setShowUiMenu] = (0, react_1.useState)(false);
185
191
  const [sortOrder, setSortOrder] = (0, react_1.useState)('newest');
192
+ // #7 — sort order for the Logs (console) tab
193
+ const [logSortOrder, setLogSortOrder] = (0, react_1.useState)('newest');
186
194
  const [reqExpanded, setReqExpanded] = (0, react_1.useState)(undefined);
187
195
  const [resExpanded, setResExpanded] = (0, react_1.useState)(undefined);
188
196
  const [showReqDiff, setShowReqDiff] = (0, react_1.useState)(false);
@@ -362,6 +370,66 @@ const NetworkInspector = ({ enabled = true, }) => {
362
370
  const badgeAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(1)).current;
363
371
  const activePulseAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0.4)).current;
364
372
  const unreadPulseAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(1)).current;
373
+ // #11 — header "clear all" icon spin/scale animation
374
+ const clearAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
375
+ // #4 — draggable floating launcher (drag anywhere on screen)
376
+ const fabPan = (0, react_1.useRef)(new react_native_1.Animated.ValueXY({ x: 0, y: 0 })).current;
377
+ const fabPanRef = (0, react_1.useRef)({ x: 0, y: 0 });
378
+ (0, react_1.useEffect)(() => {
379
+ const idX = fabPan.x.addListener(v => (fabPanRef.current.x = v.value));
380
+ const idY = fabPan.y.addListener(v => (fabPanRef.current.y = v.value));
381
+ return () => {
382
+ fabPan.x.removeListener(idX);
383
+ fabPan.y.removeListener(idY);
384
+ };
385
+ }, [fabPan]);
386
+ const fabDraggedRef = (0, react_1.useRef)(false);
387
+ const fabPanResponder = (0, react_1.useRef)(react_native_1.PanResponder.create({
388
+ // Let taps fall through to the launcher; only hijack once the
389
+ // finger actually moves, so onPress still fires on a tap.
390
+ onStartShouldSetPanResponder: () => false,
391
+ onMoveShouldSetPanResponder: (_e, g) => Math.abs(g.dx) > 4 || Math.abs(g.dy) > 4,
392
+ onPanResponderGrant: () => {
393
+ fabDraggedRef.current = true;
394
+ fabPan.setOffset({
395
+ x: fabPanRef.current.x,
396
+ y: fabPanRef.current.y,
397
+ });
398
+ fabPan.setValue({ x: 0, y: 0 });
399
+ },
400
+ onPanResponderMove: react_native_1.Animated.event([null, { dx: fabPan.x, dy: fabPan.y }], {
401
+ useNativeDriver: false,
402
+ }),
403
+ onPanResponderRelease: () => {
404
+ fabPan.flattenOffset();
405
+ // small delay so the trailing tap (if any) is ignored
406
+ setTimeout(() => {
407
+ fabDraggedRef.current = false;
408
+ }, 50);
409
+ },
410
+ onPanResponderTerminate: () => {
411
+ fabPan.flattenOffset();
412
+ fabDraggedRef.current = false;
413
+ },
414
+ })).current;
415
+ // #10 — scroll-to-top affordance for the main APIs list
416
+ const apisListRef = (0, react_1.useRef)(null);
417
+ const [showScrollTop, setShowScrollTop] = (0, react_1.useState)(false);
418
+ const runClearAllWithAnimation = (0, react_1.useCallback)(() => {
419
+ react_native_1.Animated.sequence([
420
+ react_native_1.Animated.timing(clearAnim, {
421
+ toValue: 1,
422
+ duration: 320,
423
+ useNativeDriver: true,
424
+ }),
425
+ react_native_1.Animated.timing(clearAnim, {
426
+ toValue: 0,
427
+ duration: 0,
428
+ useNativeDriver: true,
429
+ }),
430
+ ]).start();
431
+ handleClearAll();
432
+ }, [clearAnim]);
365
433
  (0, react_1.useEffect)(() => {
366
434
  if (react_native_1.Platform.OS === 'android') {
367
435
  react_native_1.UIManager.setLayoutAnimationEnabledExperimental?.(true);
@@ -519,8 +587,14 @@ const NetworkInspector = ({ enabled = true, }) => {
519
587
  }, 200);
520
588
  });
521
589
  setReduxState((0, reduxLogger_1.getReduxState)());
590
+ setReduxActionHistory([...(0, reduxLogger_1.getActionHistory)()]);
591
+ setReduxLastActionMap({ ...(0, reduxLogger_1.getLastActionForReducer)() });
522
592
  const unsubscribeRedux = (0, reduxLogger_1.subscribeReduxState)(() => {
593
+ // New references each time guarantee the Redux tab updates live, even when
594
+ // the root state object reference is unchanged or auto-refresh is paused.
523
595
  setReduxState((0, reduxLogger_1.getReduxState)());
596
+ setReduxActionHistory([...(0, reduxLogger_1.getActionHistory)()]);
597
+ setReduxLastActionMap({ ...(0, reduxLogger_1.getLastActionForReducer)() });
524
598
  });
525
599
  return () => {
526
600
  unsubscribe();
@@ -780,8 +854,12 @@ const NetworkInspector = ({ enabled = true, }) => {
780
854
  result = result.filter(log => log.message.toLowerCase().includes(s) ||
781
855
  (log.caller ?? '').toLowerCase().includes(s));
782
856
  }
857
+ // #7 — apply sort order (newest/oldest first)
858
+ result = [...result].sort((a, b) => logSortOrder === 'newest'
859
+ ? b.timestamp - a.timestamp
860
+ : a.timestamp - b.timestamp);
783
861
  return result;
784
- }, [visibleConsoleLogs, logFilters, logSearch]);
862
+ }, [visibleConsoleLogs, logFilters, logSearch, logSortOrder]);
785
863
  const filteredWebViewLogs = (0, react_1.useMemo)(() => {
786
864
  let result = webViewLogs;
787
865
  if (webViewSearch) {
@@ -907,6 +985,22 @@ const NetworkInspector = ({ enabled = true, }) => {
907
985
  ]);
908
986
  return;
909
987
  }
988
+ if (activeTab === 'redux') {
989
+ react_native_1.Alert.alert('Clear Redux Timeline', 'Are you sure you want to clear the dispatched action history?', [
990
+ { text: 'Cancel', style: 'cancel' },
991
+ {
992
+ text: 'Clear All',
993
+ onPress: () => {
994
+ (0, reduxLogger_1.clearActionHistory)();
995
+ setReduxActionHistory([]);
996
+ setReduxLastActionMap({});
997
+ },
998
+ style: 'destructive',
999
+ },
1000
+ ]);
1001
+ return;
1002
+ }
1003
+ // Default: APIs tab. Only clears NETWORK logs — never touches the other tabs.
910
1004
  if (selectedLogs.size > 0) {
911
1005
  setLogs(prev => prev.filter(l => !selectedLogs.has(l.id)));
912
1006
  setSelectedLogs(new Set());
@@ -914,10 +1008,22 @@ const NetworkInspector = ({ enabled = true, }) => {
914
1008
  else {
915
1009
  react_native_1.Alert.alert('Clear Logs', 'Are you sure you want to clear all network logs?', [
916
1010
  { text: 'Cancel', style: 'cancel' },
917
- { text: 'Clear All', onPress: handleClearAll, style: 'destructive' },
1011
+ { text: 'Clear All', onPress: clearNetworkOnly, style: 'destructive' },
918
1012
  ]);
919
1013
  }
920
1014
  }
1015
+ // Clears ONLY network logs + their derived selection/filter state.
1016
+ function clearNetworkOnly() {
1017
+ (0, networkLogger_1.clearNetworkLogs)();
1018
+ setLogs([]);
1019
+ setSelectedLogs(new Set());
1020
+ setSectionFilters({});
1021
+ setCollapsedSections(new Set());
1022
+ setStatusFilters(new Set());
1023
+ setMethodFilters(new Set());
1024
+ prevLogIdsRef.current = new Set();
1025
+ logRouteMapRef.current = new Map();
1026
+ }
921
1027
  const detailTitle = (0, react_1.useMemo)(() => {
922
1028
  if (!selected)
923
1029
  return '';
@@ -1034,7 +1140,7 @@ const NetworkInspector = ({ enabled = true, }) => {
1034
1140
  fontSize: 10.5,
1035
1141
  color: '#FFFFFF',
1036
1142
  }}>
1037
- v1.0.13
1143
+ v{constants_1.LIB_VERSION}
1038
1144
  </react_native_1.Text>
1039
1145
  </react_native_1.View>
1040
1146
  </react_native_1.View>
@@ -1202,30 +1308,56 @@ const NetworkInspector = ({ enabled = true, }) => {
1202
1308
  width: 38,
1203
1309
  height: 22,
1204
1310
  borderRadius: 11,
1205
- backgroundColor: isVisible
1206
- ? AppColors_1.AppColors.purple
1207
- : AppColors_1.AppColors.grayBorderSecondary,
1311
+ backgroundColor: isLocked
1312
+ ? AppColors_1.AppColors.grayBackground
1313
+ : isVisible
1314
+ ? AppColors_1.AppColors.purple
1315
+ : AppColors_1.AppColors.grayBorderSecondary,
1316
+ borderWidth: isLocked ? 1.5 : 0,
1317
+ borderColor: isLocked
1318
+ ? AppColors_1.AppColors.grayBorderSecondary
1319
+ : 'transparent',
1320
+ borderStyle: isLocked ? 'dashed' : 'solid',
1208
1321
  padding: 2,
1209
1322
  justifyContent: 'center',
1210
1323
  alignItems: isVisible ? 'flex-end' : 'flex-start',
1324
+ opacity: isLocked ? 0.9 : 1,
1211
1325
  }}>
1212
1326
  <react_native_1.View style={{
1213
1327
  width: 18,
1214
1328
  height: 18,
1215
1329
  borderRadius: 9,
1216
- backgroundColor: '#FFFFFF',
1330
+ backgroundColor: isLocked
1331
+ ? AppColors_1.AppColors.grayBorderSecondary
1332
+ : '#FFFFFF',
1333
+ alignItems: 'center',
1334
+ justifyContent: 'center',
1217
1335
  shadowColor: '#000',
1218
- shadowOpacity: 0.15,
1336
+ shadowOpacity: isLocked ? 0 : 0.15,
1219
1337
  shadowRadius: 1.5,
1220
1338
  shadowOffset: { width: 0, height: 1 },
1221
- }}/>
1339
+ }}>
1340
+ {isLocked && (<react_native_svg_1.default width={10} height={10} viewBox="0 0 24 24" fill="none">
1341
+ <react_native_svg_1.Path d="M7 10V7a5 5 0 0 1 10 0v3" stroke={AppColors_1.AppColors.grayText} strokeWidth="2.2" strokeLinecap="round"/>
1342
+ <react_native_svg_1.Path d="M5 10h14v9a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1z" fill={AppColors_1.AppColors.grayText}/>
1343
+ </react_native_svg_1.default>)}
1344
+ </react_native_1.View>
1222
1345
  </TouchableScale_1.default>
1346
+ {isLocked && (<react_native_1.Text style={{
1347
+ fontFamily: AppFonts_1.AppFonts.interBold,
1348
+ fontSize: 8,
1349
+ color: AppColors_1.AppColors.grayTextWeak,
1350
+ letterSpacing: 0.4,
1351
+ marginTop: 3,
1352
+ }}>
1353
+ REQUIRED
1354
+ </react_native_1.Text>)}
1223
1355
  </react_native_1.View>
1224
1356
  </react_native_1.View>);
1225
1357
  })}
1226
1358
  </react_native_1.View>
1227
1359
 
1228
- {/* Preferences Section */}
1360
+ {/* UI Preferences Section */}
1229
1361
  <react_native_1.View style={{ marginTop: 8 }}>
1230
1362
  <react_native_1.Text style={{
1231
1363
  fontFamily: AppFonts_1.AppFonts.interBold,
@@ -1234,7 +1366,7 @@ const NetworkInspector = ({ enabled = true, }) => {
1234
1366
  letterSpacing: 0.6,
1235
1367
  marginBottom: 8,
1236
1368
  }}>
1237
- PREFERENCES
1369
+ UI PREFERENCES
1238
1370
  </react_native_1.Text>
1239
1371
  <react_native_1.View style={{
1240
1372
  backgroundColor: AppColors_1.AppColors.primaryLight,
@@ -1308,6 +1440,86 @@ const NetworkInspector = ({ enabled = true, }) => {
1308
1440
  }}/>
1309
1441
  </TouchableScale_1.default>
1310
1442
  </react_native_1.View>
1443
+
1444
+ {/* Divider */}
1445
+ <react_native_1.View style={{
1446
+ height: 1,
1447
+ backgroundColor: AppColors_1.AppColors.dividerColor,
1448
+ }}/>
1449
+
1450
+ {/* Modal Height */}
1451
+ <react_native_1.View style={{
1452
+ paddingVertical: 12,
1453
+ paddingHorizontal: 14,
1454
+ }}>
1455
+ <react_native_1.View style={{
1456
+ flexDirection: 'row',
1457
+ alignItems: 'center',
1458
+ gap: 8,
1459
+ }}>
1460
+ <react_native_1.View style={{
1461
+ width: 20,
1462
+ height: 20,
1463
+ borderRadius: 6,
1464
+ backgroundColor: AppColors_1.AppColors.purpleShade50,
1465
+ borderWidth: 1,
1466
+ borderColor: 'rgba(104,75,155,0.2)',
1467
+ alignItems: 'center',
1468
+ justifyContent: 'center',
1469
+ }}>
1470
+ <NetworkIcons_1.ScreenIcon color={AppColors_1.AppColors.purple} size={11}/>
1471
+ </react_native_1.View>
1472
+ <react_native_1.View style={{ flex: 1 }}>
1473
+ <react_native_1.Text style={{
1474
+ fontFamily: AppFonts_1.AppFonts.interBold,
1475
+ fontSize: 13,
1476
+ color: AppColors_1.AppColors.primaryBlack,
1477
+ }}>
1478
+ Modal Height
1479
+ </react_native_1.Text>
1480
+ <react_native_1.Text style={{
1481
+ fontFamily: AppFonts_1.AppFonts.interRegular,
1482
+ fontSize: 11,
1483
+ color: AppColors_1.AppColors.grayText,
1484
+ marginTop: 1,
1485
+ }}>
1486
+ Height of the inspector panel relative to the screen
1487
+ </react_native_1.Text>
1488
+ </react_native_1.View>
1489
+ </react_native_1.View>
1490
+
1491
+ {/* Segmented picker */}
1492
+ <react_native_1.View style={{
1493
+ flexDirection: 'row',
1494
+ backgroundColor: AppColors_1.AppColors.grayBackground,
1495
+ borderRadius: 8,
1496
+ padding: 2.5,
1497
+ marginTop: 10,
1498
+ borderWidth: 1,
1499
+ borderColor: AppColors_1.AppColors.dividerColor,
1500
+ }}>
1501
+ {[50, 70, 90, 100].map(opt => {
1502
+ const isActive = modalHeightPercent === opt;
1503
+ return (<TouchableScale_1.default key={opt} onPress={() => setModalHeightPercent(opt)} style={{
1504
+ flex: 1,
1505
+ paddingVertical: 6,
1506
+ alignItems: 'center',
1507
+ borderRadius: 6,
1508
+ backgroundColor: isActive
1509
+ ? AppColors_1.AppColors.purple
1510
+ : 'transparent',
1511
+ }}>
1512
+ <react_native_1.Text style={{
1513
+ fontFamily: AppFonts_1.AppFonts.interBold,
1514
+ fontSize: 11,
1515
+ color: isActive ? '#FFFFFF' : AppColors_1.AppColors.grayText,
1516
+ }}>
1517
+ {opt}%
1518
+ </react_native_1.Text>
1519
+ </TouchableScale_1.default>);
1520
+ })}
1521
+ </react_native_1.View>
1522
+ </react_native_1.View>
1311
1523
  </react_native_1.View>
1312
1524
  </react_native_1.View>
1313
1525
  </react_native_1.ScrollView>
@@ -1442,11 +1654,13 @@ const NetworkInspector = ({ enabled = true, }) => {
1442
1654
  fontSize: 11,
1443
1655
  color: isActive ? '#FFFFFF' : AppColors_1.AppColors.grayText,
1444
1656
  }}>
1445
- {typeof opt === 'number' &&
1446
- opt >= 500 &&
1447
- settingsPage === 'insights'
1448
- ? `${opt}ms`
1449
- : opt}
1657
+ {opts.picker.formatLabel
1658
+ ? opts.picker.formatLabel(opt)
1659
+ : typeof opt === 'number' &&
1660
+ opt >= 500 &&
1661
+ settingsPage === 'insights'
1662
+ ? `${opt}ms`
1663
+ : opt}
1450
1664
  </react_native_1.Text>
1451
1665
  </TouchableScale_1.default>);
1452
1666
  })}
@@ -1911,7 +2125,187 @@ const NetworkInspector = ({ enabled = true, }) => {
1911
2125
  e.name === 'page_view' ||
1912
2126
  e.name === 'firebase_screen_class').length;
1913
2127
  const webviewTotal = webViewNavHistory.length;
2128
+ // --- Richer insights metrics ---
2129
+ const slowestTime = durations.length > 0 ? Math.max(...durations) : null;
2130
+ const fastestTime = durations.length > 0 ? Math.min(...durations) : null;
2131
+ const slowCount = durations.filter(d => d >= slowRequestThreshold).length;
2132
+ const status2xx = logs.filter(l => l.status != null && l.status >= 200 && l.status < 300).length;
2133
+ const status3xx = logs.filter(l => l.status != null && l.status >= 300 && l.status < 400).length;
2134
+ const status4xx = logs.filter(l => l.status != null && l.status >= 400 && l.status < 500).length;
2135
+ const status5xx = logs.filter(l => l.status != null && l.status >= 500).length;
2136
+ const totalSignals = apiTotal + logTotal + analyticsTotal + webviewTotal;
2137
+ const totalIssues = apiErrors + logErrors;
2138
+ const activeModules = [
2139
+ tabVisibility.apis,
2140
+ tabVisibility.logs,
2141
+ tabVisibility.analytics,
2142
+ tabVisibility.webview,
2143
+ tabVisibility.redux,
2144
+ ].filter(Boolean).length;
2145
+ // Composite health score: success rate penalised by error volume and slow requests.
2146
+ const healthScore = totalSignals === 0
2147
+ ? 100
2148
+ : Math.max(0, Math.min(100, Math.round(apiSuccessRate -
2149
+ (logErrors > 0 ? Math.min(15, logErrors * 3) : 0) -
2150
+ (slowCount > 0 ? Math.min(10, slowCount * 2) : 0))));
2151
+ const healthColor = healthScore >= 90
2152
+ ? AppColors_1.AppColors.greenColor
2153
+ : healthScore >= 70
2154
+ ? AppColors_1.AppColors.warningIconGold
2155
+ : AppColors_1.AppColors.errorColor;
2156
+ const healthLabel = healthScore >= 90
2157
+ ? 'Healthy'
2158
+ : healthScore >= 70
2159
+ ? 'Needs attention'
2160
+ : 'Degraded';
1914
2161
  return (<react_native_1.View style={styles_1.default.dashboardContainer}>
2162
+ {/* Overview hero card */}
2163
+ <react_native_1.View style={{
2164
+ backgroundColor: AppColors_1.AppColors.primaryLight,
2165
+ borderRadius: 14,
2166
+ borderWidth: 1,
2167
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
2168
+ padding: 16,
2169
+ marginBottom: 12,
2170
+ }}>
2171
+ <react_native_1.View style={{
2172
+ flexDirection: 'row',
2173
+ alignItems: 'center',
2174
+ gap: 14,
2175
+ }}>
2176
+ {/* Health ring stand-in */}
2177
+ <react_native_1.View style={{
2178
+ width: 64,
2179
+ height: 64,
2180
+ borderRadius: 32,
2181
+ borderWidth: 4,
2182
+ borderColor: healthColor,
2183
+ alignItems: 'center',
2184
+ justifyContent: 'center',
2185
+ backgroundColor: AppColors_1.AppColors.purpleShade50,
2186
+ }}>
2187
+ <react_native_1.Text style={{
2188
+ fontFamily: AppFonts_1.AppFonts.interBold,
2189
+ fontSize: 18,
2190
+ color: healthColor,
2191
+ }}>
2192
+ {healthScore}
2193
+ </react_native_1.Text>
2194
+ <react_native_1.Text style={{
2195
+ fontFamily: AppFonts_1.AppFonts.interMedium,
2196
+ fontSize: 7.5,
2197
+ color: AppColors_1.AppColors.grayTextWeak,
2198
+ letterSpacing: 0.4,
2199
+ }}>
2200
+ HEALTH
2201
+ </react_native_1.Text>
2202
+ </react_native_1.View>
2203
+ <react_native_1.View style={{ flex: 1 }}>
2204
+ <react_native_1.Text style={{
2205
+ fontFamily: AppFonts_1.AppFonts.interBold,
2206
+ fontSize: 15,
2207
+ color: AppColors_1.AppColors.primaryBlack,
2208
+ }}>
2209
+ Session Overview
2210
+ </react_native_1.Text>
2211
+ <react_native_1.View style={{
2212
+ flexDirection: 'row',
2213
+ alignItems: 'center',
2214
+ gap: 6,
2215
+ marginTop: 3,
2216
+ }}>
2217
+ <react_native_1.View style={{
2218
+ width: 7,
2219
+ height: 7,
2220
+ borderRadius: 3.5,
2221
+ backgroundColor: healthColor,
2222
+ }}/>
2223
+ <react_native_1.Text style={{
2224
+ fontFamily: AppFonts_1.AppFonts.interMedium,
2225
+ fontSize: 11.5,
2226
+ color: healthColor,
2227
+ }}>
2228
+ {healthLabel}
2229
+ </react_native_1.Text>
2230
+ <react_native_1.Text style={{
2231
+ fontFamily: AppFonts_1.AppFonts.interRegular,
2232
+ fontSize: 11.5,
2233
+ color: AppColors_1.AppColors.grayTextWeak,
2234
+ }}>
2235
+ • {activeModules} modules active
2236
+ </react_native_1.Text>
2237
+ </react_native_1.View>
2238
+ </react_native_1.View>
2239
+ </react_native_1.View>
2240
+
2241
+ {/* Quick totals strip */}
2242
+ <react_native_1.View style={{
2243
+ flexDirection: 'row',
2244
+ marginTop: 14,
2245
+ borderTopWidth: 1,
2246
+ borderTopColor: AppColors_1.AppColors.dividerColor,
2247
+ paddingTop: 12,
2248
+ }}>
2249
+ <react_native_1.View style={{ flex: 1, alignItems: 'center' }}>
2250
+ <react_native_1.Text style={{
2251
+ fontFamily: AppFonts_1.AppFonts.interBold,
2252
+ fontSize: 16,
2253
+ color: AppColors_1.AppColors.primaryBlack,
2254
+ }}>
2255
+ {totalSignals}
2256
+ </react_native_1.Text>
2257
+ <react_native_1.Text style={{
2258
+ fontFamily: AppFonts_1.AppFonts.interRegular,
2259
+ fontSize: 10,
2260
+ color: AppColors_1.AppColors.grayTextWeak,
2261
+ marginTop: 1,
2262
+ }}>
2263
+ Signals
2264
+ </react_native_1.Text>
2265
+ </react_native_1.View>
2266
+ <react_native_1.View style={{ width: 1, backgroundColor: AppColors_1.AppColors.dividerColor }}/>
2267
+ <react_native_1.View style={{ flex: 1, alignItems: 'center' }}>
2268
+ <react_native_1.Text style={{
2269
+ fontFamily: AppFonts_1.AppFonts.interBold,
2270
+ fontSize: 16,
2271
+ color: totalIssues > 0
2272
+ ? AppColors_1.AppColors.errorColor
2273
+ : AppColors_1.AppColors.primaryBlack,
2274
+ }}>
2275
+ {totalIssues}
2276
+ </react_native_1.Text>
2277
+ <react_native_1.Text style={{
2278
+ fontFamily: AppFonts_1.AppFonts.interRegular,
2279
+ fontSize: 10,
2280
+ color: AppColors_1.AppColors.grayTextWeak,
2281
+ marginTop: 1,
2282
+ }}>
2283
+ Issues
2284
+ </react_native_1.Text>
2285
+ </react_native_1.View>
2286
+ <react_native_1.View style={{ width: 1, backgroundColor: AppColors_1.AppColors.dividerColor }}/>
2287
+ <react_native_1.View style={{ flex: 1, alignItems: 'center' }}>
2288
+ <react_native_1.Text style={{
2289
+ fontFamily: AppFonts_1.AppFonts.interBold,
2290
+ fontSize: 16,
2291
+ color: slowCount > 0
2292
+ ? AppColors_1.AppColors.warningIconGold
2293
+ : AppColors_1.AppColors.primaryBlack,
2294
+ }}>
2295
+ {slowCount}
2296
+ </react_native_1.Text>
2297
+ <react_native_1.Text style={{
2298
+ fontFamily: AppFonts_1.AppFonts.interRegular,
2299
+ fontSize: 10,
2300
+ color: AppColors_1.AppColors.grayTextWeak,
2301
+ marginTop: 1,
2302
+ }}>
2303
+ Slow ({slowRequestThreshold}ms+)
2304
+ </react_native_1.Text>
2305
+ </react_native_1.View>
2306
+ </react_native_1.View>
2307
+ </react_native_1.View>
2308
+
1915
2309
  {/* Module 1: APIs */}
1916
2310
  {tabVisibility.apis && (<TouchableScale_1.default style={styles_1.default.dashboardModuleCard} onPress={() => switchActiveTab('apis')}>
1917
2311
  <react_native_1.View style={styles_1.default.dashboardModuleHeader}>
@@ -1951,9 +2345,75 @@ const NetworkInspector = ({ enabled = true, }) => {
1951
2345
  <react_native_1.Text style={styles_1.default.dashboardGridLbl}>Avg Latency</react_native_1.Text>
1952
2346
  </react_native_1.View>
1953
2347
  </react_native_1.View>
1954
- </TouchableScale_1.default>)}
1955
2348
 
1956
- {/* Module 2: Logs */}
2349
+ {/* Status-class breakdown + latency range */}
2350
+ <react_native_1.View style={{
2351
+ marginTop: 10,
2352
+ paddingTop: 10,
2353
+ borderTopWidth: 1,
2354
+ borderTopColor: AppColors_1.AppColors.dividerColor,
2355
+ flexDirection: 'row',
2356
+ alignItems: 'center',
2357
+ flexWrap: 'wrap',
2358
+ gap: 6,
2359
+ }}>
2360
+ {[
2361
+ { label: '2xx', value: status2xx, color: AppColors_1.AppColors.greenColor },
2362
+ { label: '3xx', value: status3xx, color: AppColors_1.AppColors.skyBlue },
2363
+ {
2364
+ label: '4xx',
2365
+ value: status4xx,
2366
+ color: AppColors_1.AppColors.warningIconGold,
2367
+ },
2368
+ { label: '5xx', value: status5xx, color: AppColors_1.AppColors.errorColor },
2369
+ ].map(s => (<react_native_1.View key={s.label} style={{
2370
+ flexDirection: 'row',
2371
+ alignItems: 'center',
2372
+ gap: 4,
2373
+ backgroundColor: AppColors_1.AppColors.grayBackground,
2374
+ borderRadius: 6,
2375
+ borderWidth: 1,
2376
+ borderColor: AppColors_1.AppColors.dividerColor,
2377
+ paddingHorizontal: 7,
2378
+ paddingVertical: 3,
2379
+ }}>
2380
+ <react_native_1.View style={{
2381
+ width: 6,
2382
+ height: 6,
2383
+ borderRadius: 3,
2384
+ backgroundColor: s.color,
2385
+ }}/>
2386
+ <react_native_1.Text style={{
2387
+ fontFamily: AppFonts_1.AppFonts.interBold,
2388
+ fontSize: 10,
2389
+ color: AppColors_1.AppColors.grayTextStrong,
2390
+ }}>
2391
+ {s.label} {s.value}
2392
+ </react_native_1.Text>
2393
+ </react_native_1.View>))}
2394
+ {slowestTime != null && (<react_native_1.View style={{
2395
+ marginLeft: 'auto',
2396
+ flexDirection: 'row',
2397
+ alignItems: 'center',
2398
+ gap: 4,
2399
+ }}>
2400
+ <react_native_1.Text style={{
2401
+ fontFamily: AppFonts_1.AppFonts.interRegular,
2402
+ fontSize: 10,
2403
+ color: AppColors_1.AppColors.grayTextWeak,
2404
+ }}>
2405
+ Range
2406
+ </react_native_1.Text>
2407
+ <react_native_1.Text style={{
2408
+ fontFamily: AppFonts_1.AppFonts.interBold,
2409
+ fontSize: 10,
2410
+ color: AppColors_1.AppColors.grayTextStrong,
2411
+ }}>
2412
+ {fastestTime}–{slowestTime}ms
2413
+ </react_native_1.Text>
2414
+ </react_native_1.View>)}
2415
+ </react_native_1.View>
2416
+ </TouchableScale_1.default>)}
1957
2417
  {tabVisibility.logs && (<TouchableScale_1.default style={styles_1.default.dashboardModuleCard} onPress={() => switchActiveTab('logs')}>
1958
2418
  <react_native_1.View style={styles_1.default.dashboardModuleHeader}>
1959
2419
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
@@ -2157,54 +2617,11 @@ const NetworkInspector = ({ enabled = true, }) => {
2157
2617
  <react_native_1.Text style={styles_1.default.emptySub}>Connected store state is empty.</react_native_1.Text>
2158
2618
  </react_native_1.View>);
2159
2619
  }
2160
- // Build hierarchical tree: Store -> Reducers -> Action -> Data
2161
- const lastActionMap = (0, reduxLogger_1.getLastActionForReducer)();
2162
- const actionHistory = (0, reduxLogger_1.getActionHistory)();
2620
+ // Build hierarchical tree: Store -> Reducers -> Action -> Data.
2621
+ // These come from component state (refreshed on every dispatch) so the view stays live.
2622
+ const lastActionMap = reduxLastActionMap;
2623
+ const actionHistory = reduxActionHistory;
2163
2624
  return (<react_native_1.ScrollView style={styles_1.default.detailScroll} contentContainerStyle={{ paddingBottom: 24 }}>
2164
- {/* Top Summary Card */}
2165
- <react_native_1.View style={{
2166
- backgroundColor: AppColors_1.AppColors.primaryLight,
2167
- borderRadius: 12,
2168
- borderWidth: 1,
2169
- borderColor: AppColors_1.AppColors.grayBorderSecondary,
2170
- padding: 14,
2171
- marginHorizontal: 16,
2172
- marginTop: 12,
2173
- marginBottom: 12,
2174
- flexDirection: 'row',
2175
- alignItems: 'center',
2176
- gap: 12,
2177
- }}>
2178
- <react_native_1.View style={{
2179
- width: 44,
2180
- height: 44,
2181
- borderRadius: 10,
2182
- backgroundColor: AppColors_1.AppColors.purpleShade50,
2183
- alignItems: 'center',
2184
- justifyContent: 'center',
2185
- }}>
2186
- <NetworkIcons_1.TerminalIcon color={AppColors_1.AppColors.purple} size={20}/>
2187
- </react_native_1.View>
2188
- <react_native_1.View style={{ flex: 1 }}>
2189
- <react_native_1.Text style={{
2190
- fontFamily: AppFonts_1.AppFonts.interBold,
2191
- fontSize: 13,
2192
- color: AppColors_1.AppColors.primaryBlack,
2193
- }}>
2194
- Redux Store Snapshot
2195
- </react_native_1.Text>
2196
- <react_native_1.Text style={{
2197
- fontFamily: AppFonts_1.AppFonts.interRegular,
2198
- fontSize: 11,
2199
- color: AppColors_1.AppColors.grayText,
2200
- marginTop: 2,
2201
- }}>
2202
- Total size: {(0, helpers_1.getSize)(reduxState)} • {reducerKeys.length} Reducers
2203
- </react_native_1.Text>
2204
- </react_native_1.View>
2205
- <CopyButton_1.default value={() => reduxState} label="Overall Store"/>
2206
- </react_native_1.View>
2207
-
2208
2625
  {/* Tab View Selection Segments */}
2209
2626
  <react_native_1.View style={{
2210
2627
  flexDirection: 'row',
@@ -2212,6 +2629,7 @@ const NetworkInspector = ({ enabled = true, }) => {
2212
2629
  borderRadius: 10,
2213
2630
  padding: 3,
2214
2631
  marginHorizontal: 16,
2632
+ marginTop: 12,
2215
2633
  marginBottom: 12,
2216
2634
  borderWidth: 1,
2217
2635
  borderColor: AppColors_1.AppColors.dividerColor,
@@ -2229,15 +2647,46 @@ const NetworkInspector = ({ enabled = true, }) => {
2229
2647
  ? AppColors_1.AppColors.purple
2230
2648
  : 'transparent',
2231
2649
  }}>
2232
- <react_native_1.Text style={{
2650
+ <react_native_1.View style={{
2651
+ flexDirection: 'row',
2652
+ alignItems: 'center',
2653
+ justifyContent: 'center',
2654
+ gap: 6,
2655
+ }}>
2656
+ <ReduxTreeView_1.ReduxTimelineIcon color={reduxActiveSubTab === 'timeline'
2657
+ ? '#FFFFFF'
2658
+ : AppColors_1.AppColors.grayText} size={13}/>
2659
+ <react_native_1.Text style={{
2233
2660
  fontFamily: AppFonts_1.AppFonts.interBold,
2234
2661
  fontSize: 11,
2235
2662
  color: reduxActiveSubTab === 'timeline'
2236
2663
  ? '#FFFFFF'
2237
2664
  : AppColors_1.AppColors.grayText,
2238
2665
  }}>
2239
- Action Timeline
2240
- </react_native_1.Text>
2666
+ Action Timeline
2667
+ </react_native_1.Text>
2668
+ <react_native_1.View style={{
2669
+ minWidth: 18,
2670
+ paddingHorizontal: 5,
2671
+ height: 16,
2672
+ borderRadius: 8,
2673
+ alignItems: 'center',
2674
+ justifyContent: 'center',
2675
+ backgroundColor: reduxActiveSubTab === 'timeline'
2676
+ ? 'rgba(255,255,255,0.28)'
2677
+ : AppColors_1.AppColors.dividerColor,
2678
+ }}>
2679
+ <react_native_1.Text style={{
2680
+ fontFamily: AppFonts_1.AppFonts.interBold,
2681
+ fontSize: 9,
2682
+ color: reduxActiveSubTab === 'timeline'
2683
+ ? '#FFFFFF'
2684
+ : AppColors_1.AppColors.grayText,
2685
+ }}>
2686
+ {actionHistory.length}
2687
+ </react_native_1.Text>
2688
+ </react_native_1.View>
2689
+ </react_native_1.View>
2241
2690
  </react_native_1.TouchableOpacity>
2242
2691
  <react_native_1.TouchableOpacity onPress={() => {
2243
2692
  animateNextLayout();
@@ -2250,13 +2699,44 @@ const NetworkInspector = ({ enabled = true, }) => {
2250
2699
  borderRadius: 8,
2251
2700
  backgroundColor: reduxActiveSubTab === 'tree' ? AppColors_1.AppColors.purple : 'transparent',
2252
2701
  }}>
2253
- <react_native_1.Text style={{
2702
+ <react_native_1.View style={{
2703
+ flexDirection: 'row',
2704
+ alignItems: 'center',
2705
+ justifyContent: 'center',
2706
+ gap: 6,
2707
+ }}>
2708
+ <ReduxTreeView_1.ReduxTreeIcon color={reduxActiveSubTab === 'tree' ? '#FFFFFF' : AppColors_1.AppColors.grayText} size={13}/>
2709
+ <react_native_1.Text style={{
2254
2710
  fontFamily: AppFonts_1.AppFonts.interBold,
2255
2711
  fontSize: 11,
2256
- color: reduxActiveSubTab === 'tree' ? '#FFFFFF' : AppColors_1.AppColors.grayText,
2712
+ color: reduxActiveSubTab === 'tree'
2713
+ ? '#FFFFFF'
2714
+ : AppColors_1.AppColors.grayText,
2257
2715
  }}>
2258
- 🏪 Store Tree
2259
- </react_native_1.Text>
2716
+ Store Tree
2717
+ </react_native_1.Text>
2718
+ <react_native_1.View style={{
2719
+ minWidth: 18,
2720
+ paddingHorizontal: 5,
2721
+ height: 16,
2722
+ borderRadius: 8,
2723
+ alignItems: 'center',
2724
+ justifyContent: 'center',
2725
+ backgroundColor: reduxActiveSubTab === 'tree'
2726
+ ? 'rgba(255,255,255,0.28)'
2727
+ : AppColors_1.AppColors.dividerColor,
2728
+ }}>
2729
+ <react_native_1.Text style={{
2730
+ fontFamily: AppFonts_1.AppFonts.interBold,
2731
+ fontSize: 9,
2732
+ color: reduxActiveSubTab === 'tree'
2733
+ ? '#FFFFFF'
2734
+ : AppColors_1.AppColors.grayText,
2735
+ }}>
2736
+ {reducerKeys.length}
2737
+ </react_native_1.Text>
2738
+ </react_native_1.View>
2739
+ </react_native_1.View>
2260
2740
  </react_native_1.TouchableOpacity>
2261
2741
  </react_native_1.View>
2262
2742
 
@@ -2302,27 +2782,36 @@ const NetworkInspector = ({ enabled = true, }) => {
2302
2782
  };
2303
2783
  return (<>
2304
2784
  {hasNavigationContext && (<NavigationTracker onStateChange={setNavState}/>)}
2305
- <TouchableScale_1.default style={styles_1.default.fabWrapper} onPress={() => setVisible(true)} hitSlop={10}>
2306
- <react_native_1.Animated.View style={[styles_1.default.fabPulseRing, { transform: [{ scale: pulseAnim }] }]}/>
2307
- <NetworkIcons_1.BrandCircleIcon size={62}/>
2308
- {(logs.length > 0 || analyticsEvents.length > 0) && (<react_native_1.Animated.View style={[
2785
+ <react_native_1.Animated.View style={[styles_1.default.fabWrapper, { transform: fabPan.getTranslateTransform() }]} {...fabPanResponder.panHandlers}>
2786
+ <TouchableScale_1.default style={{ alignItems: 'center', justifyContent: 'center' }} onPress={() => {
2787
+ if (fabDraggedRef.current)
2788
+ return;
2789
+ setVisible(true);
2790
+ }} hitSlop={10}>
2791
+ <react_native_1.Animated.View style={[styles_1.default.fabPulseRing, { transform: [{ scale: pulseAnim }] }]}/>
2792
+ <NetworkIcons_1.BrandCircleIcon size={62}/>
2793
+ {(logs.length > 0 || analyticsEvents.length > 0) && (<react_native_1.Animated.View style={[
2309
2794
  styles_1.default.fabBadge,
2310
2795
  hasErrors ? styles_1.default.fabBadgeError : styles_1.default.fabBadgeNormal,
2311
2796
  { transform: [{ scale: badgeAnim }] },
2312
2797
  ]}>
2313
- <react_native_1.Text style={styles_1.default.fabBadgeText}>
2314
- {logs.length + analyticsEvents.length > 99
2798
+ <react_native_1.Text style={styles_1.default.fabBadgeText}>
2799
+ {logs.length + analyticsEvents.length > 99
2315
2800
  ? '99+'
2316
2801
  : logs.length + analyticsEvents.length}
2317
- </react_native_1.Text>
2318
- </react_native_1.Animated.View>)}
2319
- </TouchableScale_1.default>
2802
+ </react_native_1.Text>
2803
+ </react_native_1.Animated.View>)}
2804
+ </TouchableScale_1.default>
2805
+ </react_native_1.Animated.View>
2320
2806
 
2321
2807
  <react_native_1.Modal visible={visible} animationType="slide" transparent>
2322
2808
  {visible && (<ErrorBoundary_1.default onClose={closeModal}>
2323
2809
  <react_native_1.View style={styles_1.default.modalBackdrop}>
2324
2810
  <react_native_1.Pressable style={styles_1.default.modalBackdropPressable} onPress={closeModal}/>
2325
- <react_native_1.View style={styles_1.default.modalContentCard}>
2811
+ <react_native_1.View style={[
2812
+ styles_1.default.modalContentCard,
2813
+ { height: `${modalHeightPercent}%` },
2814
+ ]}>
2326
2815
  <react_native_1.StatusBar translucent backgroundColor="transparent" barStyle="light-content"/>
2327
2816
 
2328
2817
  <react_native_linear_gradient_1.default colors={[AppColors_1.AppColors.purple, '#6B4EFF']} style={styles_1.default.headerGradient}>
@@ -2343,10 +2832,27 @@ const NetworkInspector = ({ enabled = true, }) => {
2343
2832
  setSelectedEvent(null);
2344
2833
  });
2345
2834
  }} hitSlop={15} style={[
2346
- styles_1.default.iconBtnMinimal,
2835
+ {
2836
+ width: 38,
2837
+ height: 38,
2838
+ borderRadius: 19,
2839
+ alignItems: 'center',
2840
+ justifyContent: 'center',
2841
+ backgroundColor: 'rgba(255,255,255,0.18)',
2842
+ borderWidth: 1,
2843
+ borderColor: 'rgba(255,255,255,0.30)',
2844
+ },
2347
2845
  selected == null &&
2348
2846
  selectedEvent == null && { display: 'none' },
2349
2847
  ]}>
2848
+ {/* Soft outer glow to fake a blurred circle */}
2849
+ <react_native_1.View style={{
2850
+ position: 'absolute',
2851
+ width: 48,
2852
+ height: 48,
2853
+ borderRadius: 24,
2854
+ backgroundColor: 'rgba(255,255,255,0.10)',
2855
+ }}/>
2350
2856
  <NetworkIcons_1.WhiteBackNavigation />
2351
2857
  </TouchableScale_1.default>
2352
2858
 
@@ -2357,8 +2863,8 @@ const NetworkInspector = ({ enabled = true, }) => {
2357
2863
  flex: 1,
2358
2864
  }}>
2359
2865
  <react_native_1.View style={{
2360
- width: 42,
2361
- height: 42,
2866
+ width: 50,
2867
+ height: 50,
2362
2868
  borderRadius: 10,
2363
2869
  backgroundColor: 'rgba(255,255,255,0.13)',
2364
2870
  borderWidth: 1.5,
@@ -2370,37 +2876,92 @@ const NetworkInspector = ({ enabled = true, }) => {
2370
2876
  shadowRadius: 4,
2371
2877
  shadowOffset: { width: 0, height: 2 },
2372
2878
  }}>
2373
- <NetworkIcons_1.BrandSquareIcon size={36}/>
2879
+ <NetworkIcons_1.BrandSquareIcon size={45}/>
2374
2880
  </react_native_1.View>
2375
2881
  <react_native_1.View style={{ gap: 3 }}>
2376
- <react_native_1.Text style={[
2377
- styles_1.default.headerTitle,
2378
- { fontSize: 17, letterSpacing: 0.2 },
2379
- ]}>
2882
+ <react_native_1.Text style={[styles_1.default.headerTitle]}>
2380
2883
  RN InApp Inspector
2381
2884
  </react_native_1.Text>
2382
2885
  <react_native_1.View style={{
2383
2886
  flexDirection: 'row',
2384
2887
  alignItems: 'center',
2385
- gap: 5,
2888
+ gap: 6,
2386
2889
  }}>
2387
- <react_native_1.Animated.View style={{
2388
- width: 6,
2389
- height: 6,
2390
- borderRadius: 3,
2391
- backgroundColor: '#4ADE80',
2392
- opacity: activePulseAnim,
2393
- }}/>
2394
- <react_native_1.Text style={{
2890
+ {/* OS chip */}
2891
+ <react_native_1.View style={{
2892
+ flexDirection: 'row',
2893
+ alignItems: 'center',
2894
+ borderRadius: 6,
2895
+ overflow: 'hidden',
2896
+ borderWidth: 1,
2897
+ borderColor: 'rgba(255,255,255,0.18)',
2898
+ }}>
2899
+ <react_native_1.View style={{
2900
+ paddingHorizontal: 5,
2901
+ paddingVertical: 2,
2902
+ backgroundColor: 'rgba(255,255,255,0.28)',
2903
+ }}>
2904
+ <react_native_1.Text style={{
2905
+ fontFamily: AppFonts_1.AppFonts.interBold,
2906
+ fontSize: 9,
2907
+ color: '#FFFFFF',
2908
+ letterSpacing: 0.3,
2909
+ }}>
2910
+ {react_native_1.Platform.OS === 'ios' ? 'iOS' : 'Android'}
2911
+ </react_native_1.Text>
2912
+ </react_native_1.View>
2913
+ <react_native_1.View style={{
2914
+ paddingHorizontal: 5,
2915
+ paddingVertical: 2,
2916
+ backgroundColor: 'rgba(255,255,255,0.12)',
2917
+ }}>
2918
+ <react_native_1.Text style={{
2395
2919
  fontFamily: AppFonts_1.AppFonts.interMedium,
2396
- fontSize: 10,
2397
- color: 'rgba(255,255,255,0.78)',
2920
+ fontSize: 9.5,
2921
+ color: 'rgba(255,255,255,0.92)',
2922
+ }}>
2923
+ {String(react_native_1.Platform.Version)}
2924
+ </react_native_1.Text>
2925
+ </react_native_1.View>
2926
+ </react_native_1.View>
2927
+
2928
+ {/* npm chip */}
2929
+ <react_native_1.View style={{
2930
+ flexDirection: 'row',
2931
+ alignItems: 'center',
2932
+ borderRadius: 6,
2933
+ overflow: 'hidden',
2934
+ borderWidth: 1,
2935
+ borderColor: 'rgba(255,255,255,0.18)',
2936
+ }}>
2937
+ <react_native_1.View style={{
2938
+ paddingHorizontal: 5,
2939
+ paddingVertical: 2,
2940
+ backgroundColor: 'rgba(255,255,255,0.28)',
2941
+ }}>
2942
+ <react_native_1.Text style={{
2943
+ fontFamily: AppFonts_1.AppFonts.interBold,
2944
+ fontSize: 9,
2945
+ color: '#FFFFFF',
2398
2946
  letterSpacing: 0.3,
2399
2947
  }}>
2400
- Active •{' '}
2401
- {react_native_1.Platform.OS === 'ios' ? 'iOS' : 'Android'}{' '}
2402
- (v1.0.13)
2403
- </react_native_1.Text>
2948
+ npm
2949
+ </react_native_1.Text>
2950
+ </react_native_1.View>
2951
+ <react_native_1.View style={{
2952
+ paddingHorizontal: 5,
2953
+ paddingVertical: 2,
2954
+ backgroundColor: 'rgba(255,255,255,0.12)',
2955
+ }}>
2956
+ <react_native_1.Text style={{
2957
+ fontFamily: AppFonts_1.AppFonts.interMedium,
2958
+ fontSize: 9.5,
2959
+ color: 'rgba(255,255,255,0.92)',
2960
+ }}>
2961
+ v{constants_1.LIB_VERSION}
2962
+ </react_native_1.Text>
2963
+ </react_native_1.View>
2964
+ </react_native_1.View>
2404
2965
  </react_native_1.View>
2405
2966
  </react_native_1.View>
2406
2967
  </react_native_1.View>) : null}
@@ -2425,21 +2986,48 @@ const NetworkInspector = ({ enabled = true, }) => {
2425
2986
  </react_native_1.Text>
2426
2987
  </react_native_1.View>
2427
2988
  <react_native_1.View style={styles_1.default.headerDetailSubRow}>
2428
- <react_native_1.View style={[
2989
+ <react_native_1.View style={{
2990
+ flexDirection: 'row',
2991
+ alignItems: 'center',
2992
+ gap: 5,
2993
+ paddingHorizontal: 8,
2994
+ paddingVertical: 3,
2995
+ borderRadius: 20,
2996
+ backgroundColor: `${(0, helpers_1.getStatusColor)(selected.status)}26`,
2997
+ borderWidth: 1,
2998
+ borderColor: `${(0, helpers_1.getStatusColor)(selected.status)}55`,
2999
+ }}>
3000
+ <react_native_1.View style={[
2429
3001
  styles_1.default.headerStatusDot,
2430
3002
  {
2431
3003
  backgroundColor: (0, helpers_1.getStatusColor)(selected.status),
2432
3004
  },
2433
3005
  ]}/>
2434
- <react_native_1.Text style={styles_1.default.headerSubTitle}>
2435
- {selected.status === 0
3006
+ <react_native_1.Text style={[
3007
+ styles_1.default.headerSubTitle,
3008
+ { fontFamily: AppFonts_1.AppFonts.interBold },
3009
+ ]}>
3010
+ {selected.status === 0
2436
3011
  ? 'Failed'
2437
- : selected.status ?? 'Pending'}{' '}
2438
- •{' '}
2439
- {selected.duration != null
3012
+ : selected.status ?? 'Pending'}
3013
+ </react_native_1.Text>
3014
+ </react_native_1.View>
3015
+ <react_native_1.View style={{
3016
+ flexDirection: 'row',
3017
+ alignItems: 'center',
3018
+ gap: 4,
3019
+ paddingHorizontal: 8,
3020
+ paddingVertical: 3,
3021
+ borderRadius: 20,
3022
+ backgroundColor: 'rgba(255,255,255,0.16)',
3023
+ }}>
3024
+ <NetworkIcons_1.ClockIcon color="#FFFFFF" size={11}/>
3025
+ <react_native_1.Text style={styles_1.default.headerSubTitle}>
3026
+ {selected.duration != null
2440
3027
  ? `${selected.duration}ms`
2441
- : '-'}
2442
- </react_native_1.Text>
3028
+ : ''}
3029
+ </react_native_1.Text>
3030
+ </react_native_1.View>
2443
3031
  </react_native_1.View>
2444
3032
  </react_native_1.View>) : selectedEvent != null ? (<react_native_1.View style={styles_1.default.headerDetailCenter}>
2445
3033
  <react_native_1.View style={styles_1.default.headerDetailRow}>
@@ -2482,7 +3070,50 @@ const NetworkInspector = ({ enabled = true, }) => {
2482
3070
  </react_native_1.View>) : null}
2483
3071
  </react_native_1.View>
2484
3072
 
2485
- <react_native_1.View style={styles_1.default.headerRight}>
3073
+ <react_native_1.View style={[
3074
+ styles_1.default.headerRight,
3075
+ selected == null &&
3076
+ selectedEvent == null && {
3077
+ flexShrink: 0,
3078
+ minWidth: 116,
3079
+ },
3080
+ ]}>
3081
+ {selected == null && selectedEvent == null && (<TouchableScale_1.default onPress={() => {
3082
+ react_native_1.Alert.alert('Clear Everything', 'This clears all tabs — APIs, Logs, Analytics, WebView and Redux timeline. Continue?', [
3083
+ { text: 'Cancel', style: 'cancel' },
3084
+ {
3085
+ text: 'Clear All',
3086
+ onPress: runClearAllWithAnimation,
3087
+ style: 'destructive',
3088
+ },
3089
+ ]);
3090
+ }} hitSlop={15} style={[
3091
+ styles_1.default.closeButtonSquare,
3092
+ {
3093
+ marginRight: 8,
3094
+ backgroundColor: 'rgba(255,255,255,0.15)',
3095
+ },
3096
+ ]}>
3097
+ <react_native_1.Animated.View style={{
3098
+ transform: [
3099
+ {
3100
+ rotate: clearAnim.interpolate({
3101
+ inputRange: [0, 1],
3102
+ outputRange: ['0deg', '-25deg'],
3103
+ }),
3104
+ },
3105
+ {
3106
+ scale: clearAnim.interpolate({
3107
+ inputRange: [0, 0.5, 1],
3108
+ outputRange: [1, 1.25, 1],
3109
+ }),
3110
+ },
3111
+ ],
3112
+ }}>
3113
+ <NetworkIcons_1.TrashIcon color="#FFFFFF" size={15}/>
3114
+ </react_native_1.Animated.View>
3115
+ </TouchableScale_1.default>)}
3116
+
2486
3117
  {selected == null && selectedEvent == null && (<TouchableScale_1.default onPress={() => setSettingsPage('main')} hitSlop={15} style={[
2487
3118
  styles_1.default.closeButtonSquare,
2488
3119
  {
@@ -2817,50 +3448,53 @@ const NetworkInspector = ({ enabled = true, }) => {
2817
3448
  filteredAnalyticsEvents.length === 0 && {
2818
3449
  flexGrow: 1,
2819
3450
  },
2820
- ]} keyboardShouldPersistTaps="handled"/>)) : activeTab === 'apis' && selected == null ? (<react_native_1.FlatList data={groupedData} keyExtractor={item => item?.id?.toString()} renderItem={renderItem} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={true} ListHeaderComponent={<react_native_1.View style={{ marginTop: 8 }}>
2821
- <react_native_1.View style={styles_1.default.toolbarRow}>
2822
- <react_native_1.View style={styles_1.default.searchContainer}>
2823
- <NetworkIcons_1.SearchIcon color={AppColors_1.AppColors.grayTextWeak} size={16}/>
2824
- <react_native_1.TextInput placeholder="Search endpoints..." placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={styles_1.default.searchInput} autoCorrect={false} autoCapitalize="none"/>
2825
- {search.length > 0 && (<react_native_1.Pressable onPress={() => setSearch('')} hitSlop={10} style={styles_1.default.clearBtn}>
2826
- <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
2827
- </react_native_1.Pressable>)}
2828
- </react_native_1.View>
3451
+ ]} keyboardShouldPersistTaps="handled"/>)) : activeTab === 'apis' && selected == null ? (<react_native_1.View style={{ flex: 1 }}>
3452
+ <react_native_1.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={<react_native_1.View style={{ marginTop: 8 }}>
3453
+ <react_native_1.View style={styles_1.default.toolbarRow}>
3454
+ <react_native_1.View style={styles_1.default.searchContainer}>
3455
+ <NetworkIcons_1.SearchIcon color={AppColors_1.AppColors.grayTextWeak} size={16}/>
3456
+ <react_native_1.TextInput placeholder="Search endpoints..." placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={styles_1.default.searchInput} autoCorrect={false} autoCapitalize="none"/>
3457
+ {search.length > 0 && (<react_native_1.Pressable onPress={() => setSearch('')} hitSlop={10} style={styles_1.default.clearBtn}>
3458
+ <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
3459
+ </react_native_1.Pressable>)}
3460
+ </react_native_1.View>
2829
3461
 
2830
- <react_native_1.View style={styles_1.default.toolbarRight}>
2831
- <TouchableScale_1.default style={styles_1.default.toolbarBtn} onPress={handleDelete} hitSlop={10}>
2832
- <NetworkIcons_1.TrashIcon color={AppColors_1.AppColors.grayTextStrong} size={18}/>
2833
- {selectedLogs.size > 0 && (<react_native_1.View style={styles_1.default.trashBadge}>
2834
- <react_native_1.Text style={styles_1.default.trashBadgeText}>
2835
- {selectedLogs.size}
2836
- </react_native_1.Text>
2837
- </react_native_1.View>)}
2838
- </TouchableScale_1.default>
3462
+ <react_native_1.View style={styles_1.default.toolbarRight}>
3463
+ <TouchableScale_1.default style={styles_1.default.toolbarBtn} onPress={handleDelete} hitSlop={10}>
3464
+ <NetworkIcons_1.TrashIcon color={AppColors_1.AppColors.grayTextStrong} size={18}/>
3465
+ {selectedLogs.size > 0 && (<react_native_1.View style={styles_1.default.trashBadge}>
3466
+ <react_native_1.Text style={styles_1.default.trashBadgeText}>
3467
+ {selectedLogs.size}
3468
+ </react_native_1.Text>
3469
+ </react_native_1.View>)}
3470
+ </TouchableScale_1.default>
2839
3471
 
2840
- <TouchableScale_1.default style={styles_1.default.toolbarBtn} onPress={() => setSortOrder(o => o === 'newest' ? 'oldest' : 'newest')} hitSlop={10}>
2841
- <NetworkIcons_1.SortArrowIcon direction={sortOrder === 'newest' ? 'down' : 'up'} color={AppColors_1.AppColors.grayTextStrong} size={18}/>
2842
- </TouchableScale_1.default>
3472
+ <TouchableScale_1.default style={styles_1.default.toolbarBtn} onPress={() => setSortOrder(o => o === 'newest' ? 'oldest' : 'newest')} hitSlop={10}>
3473
+ <NetworkIcons_1.SortArrowIcon direction={sortOrder === 'newest' ? 'down' : 'up'} color={AppColors_1.AppColors.grayTextStrong} size={18}/>
3474
+ </TouchableScale_1.default>
2843
3475
 
2844
- <TouchableScale_1.default style={[
3476
+ <TouchableScale_1.default style={[
2845
3477
  styles_1.default.toolbarBtn,
2846
3478
  filtersAccordion.isOpen &&
2847
3479
  styles_1.default.toolbarBtnActive,
2848
3480
  ]} onPress={filtersAccordion.toggleOpen} hitSlop={10}>
2849
- <NetworkIcons_1.FilterIcon color={filtersAccordion.isOpen
3481
+ <NetworkIcons_1.FilterIcon color={filtersAccordion.isOpen
2850
3482
  ? AppColors_1.AppColors.purple
2851
3483
  : AppColors_1.AppColors.grayTextStrong} size={18}/>
2852
- </TouchableScale_1.default>
3484
+ </TouchableScale_1.default>
3485
+ </react_native_1.View>
2853
3486
  </react_native_1.View>
2854
- </react_native_1.View>
2855
3487
 
2856
- <react_native_1.Animated.View style={[
3488
+ <react_native_1.Animated.View style={[
2857
3489
  filtersAccordion.bodyStyle,
2858
3490
  { overflow: 'hidden' },
2859
3491
  ]}>
2860
- <react_native_1.View style={styles_1.default.filtersContainer}>
2861
- <react_native_1.Text style={styles_1.default.filtersHeading}>STATUS</react_native_1.Text>
2862
- <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles_1.default.statusRowContent}>
2863
- {constants_1.STATUS_FILTERS.map(filter => {
3492
+ <react_native_1.View style={styles_1.default.filtersContainer}>
3493
+ <react_native_1.Text style={styles_1.default.filtersHeading}>
3494
+ STATUS
3495
+ </react_native_1.Text>
3496
+ <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles_1.default.statusRowContent}>
3497
+ {constants_1.STATUS_FILTERS.map(filter => {
2864
3498
  const isAll = filter === 'ALL';
2865
3499
  const active = isAll
2866
3500
  ? statusFilters.size === 0
@@ -2879,38 +3513,38 @@ const NetworkInspector = ({ enabled = true, }) => {
2879
3513
  });
2880
3514
  }
2881
3515
  }} hitSlop={10}>
2882
- {active ? (<react_native_1.View style={[
3516
+ {active ? (<react_native_1.View style={[
2883
3517
  styles_1.default.statusFilterChip,
2884
3518
  styles_1.default.statusFilterActive,
2885
3519
  { overflow: 'hidden' },
2886
3520
  ]}>
2887
- <react_native_linear_gradient_1.default colors={[
3521
+ <react_native_linear_gradient_1.default colors={[
2888
3522
  AppColors_1.AppColors.purpleShade50,
2889
3523
  '#EAE5FF',
2890
3524
  ]} style={react_native_1.StyleSheet.absoluteFill} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }}/>
2891
- <react_native_1.Text style={[
3525
+ <react_native_1.Text style={[
2892
3526
  styles_1.default.statusFilterText,
2893
3527
  { color: AppColors_1.AppColors.purple },
2894
3528
  ]}>
2895
- {filter}
2896
- </react_native_1.Text>
2897
- </react_native_1.View>) : (<react_native_1.View style={styles_1.default.statusFilterChip}>
2898
- <react_native_1.Text style={styles_1.default.statusFilterText}>
2899
- {filter}
2900
- </react_native_1.Text>
2901
- </react_native_1.View>)}
2902
- </TouchableScale_1.default>);
3529
+ {filter}
3530
+ </react_native_1.Text>
3531
+ </react_native_1.View>) : (<react_native_1.View style={styles_1.default.statusFilterChip}>
3532
+ <react_native_1.Text style={styles_1.default.statusFilterText}>
3533
+ {filter}
3534
+ </react_native_1.Text>
3535
+ </react_native_1.View>)}
3536
+ </TouchableScale_1.default>);
2903
3537
  })}
2904
- </react_native_1.ScrollView>
3538
+ </react_native_1.ScrollView>
2905
3539
 
2906
- <react_native_1.Text style={[
3540
+ <react_native_1.Text style={[
2907
3541
  styles_1.default.filtersHeading,
2908
3542
  { marginTop: 16 },
2909
3543
  ]}>
2910
- METHOD
2911
- </react_native_1.Text>
2912
- <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles_1.default.statusRowContent}>
2913
- {availableMethods.map(filter => {
3544
+ METHOD
3545
+ </react_native_1.Text>
3546
+ <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles_1.default.statusRowContent}>
3547
+ {availableMethods.map(filter => {
2914
3548
  const isAll = filter === 'ALL';
2915
3549
  const active = isAll
2916
3550
  ? methodFilters.size === 0
@@ -2929,43 +3563,55 @@ const NetworkInspector = ({ enabled = true, }) => {
2929
3563
  });
2930
3564
  }
2931
3565
  }} hitSlop={10}>
2932
- {active ? (<react_native_1.View style={[
3566
+ {active ? (<react_native_1.View style={[
2933
3567
  styles_1.default.statusFilterChip,
2934
3568
  styles_1.default.statusFilterActive,
2935
3569
  { overflow: 'hidden' },
2936
3570
  ]}>
2937
- <react_native_linear_gradient_1.default colors={[
3571
+ <react_native_linear_gradient_1.default colors={[
2938
3572
  AppColors_1.AppColors.purpleShade50,
2939
3573
  '#EAE5FF',
2940
3574
  ]} style={react_native_1.StyleSheet.absoluteFill} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }}/>
2941
- <react_native_1.Text style={[
3575
+ <react_native_1.Text style={[
2942
3576
  styles_1.default.statusFilterText,
2943
3577
  { color: AppColors_1.AppColors.purple },
2944
3578
  ]}>
2945
- {filter}
2946
- </react_native_1.Text>
2947
- </react_native_1.View>) : (<react_native_1.View style={styles_1.default.statusFilterChip}>
2948
- <react_native_1.Text style={styles_1.default.statusFilterText}>
2949
- {filter}
2950
- </react_native_1.Text>
2951
- </react_native_1.View>)}
2952
- </TouchableScale_1.default>);
3579
+ {filter}
3580
+ </react_native_1.Text>
3581
+ </react_native_1.View>) : (<react_native_1.View style={styles_1.default.statusFilterChip}>
3582
+ <react_native_1.Text style={styles_1.default.statusFilterText}>
3583
+ {filter}
3584
+ </react_native_1.Text>
3585
+ </react_native_1.View>)}
3586
+ </TouchableScale_1.default>);
2953
3587
  })}
2954
- </react_native_1.ScrollView>
2955
- </react_native_1.View>
2956
- </react_native_1.Animated.View>
3588
+ </react_native_1.ScrollView>
3589
+ </react_native_1.View>
3590
+ </react_native_1.Animated.View>
2957
3591
 
2958
- {(search ||
3592
+ {(search ||
2959
3593
  statusFilters.size > 0 ||
2960
3594
  methodFilters.size > 0) && (<react_native_1.Text style={styles_1.default.resultCount}>
2961
- {filteredLogs.length === logs.length
3595
+ {filteredLogs.length === logs.length
2962
3596
  ? `${logs.length} requests`
2963
3597
  : `${filteredLogs.length} of ${logs.length} filtered requests`}
2964
- </react_native_1.Text>)}
2965
- </react_native_1.View>} ListEmptyComponent={<EmptyState_1.default isSearch={search.length > 0 || statusFilters.size > 0}/>} contentContainerStyle={[
3598
+ </react_native_1.Text>)}
3599
+ </react_native_1.View>} ListEmptyComponent={<EmptyState_1.default isSearch={search.length > 0 || statusFilters.size > 0}/>} contentContainerStyle={[
2966
3600
  styles_1.default.listContent,
2967
3601
  filteredLogs.length === 0 && { flexGrow: 1 },
2968
- ]} keyboardShouldPersistTaps="handled"/>) : activeTab === 'logs' ? (<react_native_1.View style={{ flex: 1 }}>
3602
+ ]} keyboardShouldPersistTaps="handled"/>
3603
+ {showScrollTop && (<TouchableScale_1.default onPress={() => {
3604
+ apisListRef.current?.scrollToOffset({
3605
+ offset: 0,
3606
+ animated: true,
3607
+ });
3608
+ setShowScrollTop(false);
3609
+ }} hitSlop={10} style={styles_1.default.scrollTopBtn}>
3610
+ <react_native_1.View style={{ transform: [{ rotate: '180deg' }] }}>
3611
+ <NetworkIcons_1.ChevronIcon color="#FFFFFF" size={18}/>
3612
+ </react_native_1.View>
3613
+ </TouchableScale_1.default>)}
3614
+ </react_native_1.View>) : activeTab === 'logs' ? (<react_native_1.View style={{ flex: 1 }}>
2969
3615
  <react_native_1.View style={{
2970
3616
  backgroundColor: '#FFFFFF',
2971
3617
  borderBottomWidth: 1,
@@ -2985,6 +3631,9 @@ const NetworkInspector = ({ enabled = true, }) => {
2985
3631
  </react_native_1.View>
2986
3632
 
2987
3633
  <react_native_1.View style={styles_1.default.toolbarRight}>
3634
+ <TouchableScale_1.default style={styles_1.default.toolbarBtn} onPress={() => setLogSortOrder(o => o === 'newest' ? 'oldest' : 'newest')} hitSlop={10}>
3635
+ <NetworkIcons_1.SortArrowIcon color={AppColors_1.AppColors.grayTextStrong} size={18} direction={logSortOrder === 'newest' ? 'down' : 'up'}/>
3636
+ </TouchableScale_1.default>
2988
3637
  <TouchableScale_1.default style={styles_1.default.toolbarBtn} onPress={handleDelete} hitSlop={10}>
2989
3638
  <NetworkIcons_1.TrashIcon color={AppColors_1.AppColors.grayTextStrong} size={18}/>
2990
3639
  </TouchableScale_1.default>
@@ -4224,7 +4873,7 @@ const NetworkInspector = ({ enabled = true, }) => {
4224
4873
  if (!resExpanded && !showResDiff)
4225
4874
  setResExpanded(true);
4226
4875
  }}/>
4227
- {showResDiff ? (<DiffViewer_1.default oldData={prevResponseData} newData={selected.response} forceOpen={resExpanded}/>) : (<JsonViewer_1.default data={selected.response} search={detailSearch} forceOpen={resExpanded}/>)}
4876
+ {showResDiff ? (<DiffViewer_1.default oldData={prevResponseData} newData={selected.response} forceOpen={resExpanded}/>) : (<JsonViewer_1.default data={selected.response} search={detailSearch} forceOpen={resExpanded} wrap/>)}
4228
4877
  </react_native_1.View>
4229
4878
  </>)}
4230
4879
  </react_native_1.ScrollView>