react-native-inapp-inspector 1.1.2 → 1.1.4
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 +30 -0
- package/dist/commonjs/components/ConsoleLogCard.js +18 -0
- package/dist/commonjs/components/LogCard.js +19 -2
- package/dist/commonjs/components/NetworkIcons.d.ts +9 -2
- package/dist/commonjs/components/NetworkIcons.js +59 -3
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/reduxLogger.d.ts +21 -7
- package/dist/commonjs/customHooks/reduxLogger.js +147 -48
- package/dist/commonjs/customHooks/webViewLogger.js +13 -8
- package/dist/commonjs/helpers/settingsStore.d.ts +28 -0
- package/dist/commonjs/helpers/settingsStore.js +92 -0
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.js +893 -185
- package/dist/commonjs/styles/index.d.ts +17 -1
- package/dist/commonjs/styles/index.js +25 -3
- package/dist/commonjs/types/index.d.ts +4 -0
- package/dist/esm/components/ConsoleLogCard.js +18 -0
- package/dist/esm/components/LogCard.js +19 -2
- package/dist/esm/components/NetworkIcons.d.ts +9 -2
- package/dist/esm/components/NetworkIcons.js +51 -2
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/reduxLogger.d.ts +21 -7
- package/dist/esm/customHooks/reduxLogger.js +145 -47
- package/dist/esm/customHooks/webViewLogger.js +13 -8
- package/dist/esm/helpers/settingsStore.d.ts +28 -0
- package/dist/esm/helpers/settingsStore.js +84 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +892 -187
- package/dist/esm/styles/index.d.ts +17 -1
- package/dist/esm/styles/index.js +25 -3
- package/dist/esm/types/index.d.ts +4 -0
- package/example/ios/example.xcodeproj/project.pbxproj +0 -8
- package/example/package-lock.json +75 -33
- package/example/package.json +1 -1
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
|
|
2
|
-
import { Alert, Animated, StyleSheet, FlatList, LayoutAnimation, Modal, PanResponder, 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, SafeAreaView, } 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';
|
|
@@ -23,8 +23,10 @@ import CodeSnippet from './components/CodeSnippet';
|
|
|
23
23
|
import AnimatedEntrance from './components/AnimatedEntrance';
|
|
24
24
|
// Helpers
|
|
25
25
|
import { formatDateTime, getStatusColor, getNavigationInfo, deduplicateLogs, getDomainColor, formatDisplayUrl, getFetchCommand, getCurlCommand, getSize, } from './helpers';
|
|
26
|
+
// #5 — settings persistence
|
|
27
|
+
import { loadSettings, saveSettings, setCustomStorage, isPersistentStorageAvailable, clearPersistedSettings, } from './helpers/settingsStore';
|
|
26
28
|
// 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, ChevronIcon, } from './components/NetworkIcons';
|
|
29
|
+
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, WipeIcon, LayersIcon, UserIcon, InfoCircleIcon, WarningTriangleIcon, ErrorCircleIcon, TrendingUpIcon, } from './components/NetworkIcons';
|
|
28
30
|
import ErrorBoundary from './components/ErrorBoundary';
|
|
29
31
|
// Stylesheet
|
|
30
32
|
import { AppColors } from './styles/AppColors';
|
|
@@ -111,7 +113,9 @@ const NavigationTracker = ({ onStateChange }) => {
|
|
|
111
113
|
const animateNextLayout = () => {
|
|
112
114
|
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
113
115
|
};
|
|
114
|
-
const NetworkInspector = ({ enabled = true, }) => {
|
|
116
|
+
const NetworkInspector = ({ enabled = true, storage, }) => {
|
|
117
|
+
// Set custom storage synchronously during render phase
|
|
118
|
+
setCustomStorage(storage || null);
|
|
115
119
|
const [isDark, setIsDark] = useState(false);
|
|
116
120
|
const [reduxState, setReduxState] = useState(null);
|
|
117
121
|
// Action timeline + per-reducer last action are kept in component state so the
|
|
@@ -193,11 +197,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
193
197
|
const visibleConsoleLogs = useMemo(() => {
|
|
194
198
|
const filtered = consoleLogs.filter(log => {
|
|
195
199
|
const type = log.type;
|
|
196
|
-
if (type === 'info' && !showConsoleLevels
|
|
200
|
+
if (type === 'info' && !showConsoleLevels?.info)
|
|
197
201
|
return false;
|
|
198
|
-
if (type === 'warn' && !showConsoleLevels
|
|
202
|
+
if (type === 'warn' && !showConsoleLevels?.warn)
|
|
199
203
|
return false;
|
|
200
|
-
if (type === 'error' && !showConsoleLevels
|
|
204
|
+
if (type === 'error' && !showConsoleLevels?.error)
|
|
201
205
|
return false;
|
|
202
206
|
const message = log.message || '';
|
|
203
207
|
const allPrefixes = [
|
|
@@ -227,9 +231,9 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
227
231
|
insights: true,
|
|
228
232
|
apis: true,
|
|
229
233
|
logs: true,
|
|
230
|
-
analytics:
|
|
231
|
-
webview:
|
|
232
|
-
redux:
|
|
234
|
+
analytics: false,
|
|
235
|
+
webview: false,
|
|
236
|
+
redux: false,
|
|
233
237
|
});
|
|
234
238
|
const [maxNetworkLogs, setMaxNetworkLogs] = useState(100);
|
|
235
239
|
const [webViewCaptureCssJs, setWebViewCaptureCssJs] = useState(true);
|
|
@@ -237,6 +241,168 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
237
241
|
const [reduxExpandDepth, setReduxExpandDepth] = useState(1);
|
|
238
242
|
const [slowRequestThreshold, setSlowRequestThreshold] = useState(1000);
|
|
239
243
|
const [insightsShowConsoleAlerts, setInsightsShowConsoleAlerts] = useState(true);
|
|
244
|
+
// #6 — tab the inspector opens on. Shown with a DEFAULT badge in Settings.
|
|
245
|
+
const [defaultTab, setDefaultTab] = useState('apis');
|
|
246
|
+
const [showDuplicateLogs, setShowDuplicateLogs] = useState(false);
|
|
247
|
+
const resetToDefaults = async () => {
|
|
248
|
+
await clearPersistedSettings();
|
|
249
|
+
setIsDark(false);
|
|
250
|
+
toggleGlobalTheme(false);
|
|
251
|
+
setModalHeightPercent(90);
|
|
252
|
+
setTabVisibility({
|
|
253
|
+
insights: true,
|
|
254
|
+
apis: true,
|
|
255
|
+
logs: true,
|
|
256
|
+
analytics: false,
|
|
257
|
+
webview: false,
|
|
258
|
+
redux: false,
|
|
259
|
+
});
|
|
260
|
+
setDefaultTab('apis');
|
|
261
|
+
setMaxNetworkLogs(100);
|
|
262
|
+
setMaxConsoleLogs(200);
|
|
263
|
+
setShowConsoleLevels({
|
|
264
|
+
info: true,
|
|
265
|
+
warn: true,
|
|
266
|
+
error: true,
|
|
267
|
+
});
|
|
268
|
+
setWebViewCaptureCssJs(true);
|
|
269
|
+
setReduxAutoRefreshState(true);
|
|
270
|
+
setReduxExpandDepth(1);
|
|
271
|
+
setSlowRequestThreshold(1000);
|
|
272
|
+
setInsightsShowConsoleAlerts(true);
|
|
273
|
+
setShowDuplicateLogs(false);
|
|
274
|
+
Alert.alert('Settings Reset', 'All settings have been reset to default values.');
|
|
275
|
+
};
|
|
276
|
+
// #5 — hydrate persisted settings once, then auto-save on any change.
|
|
277
|
+
const settingsHydratedRef = useRef(false);
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
let cancelled = false;
|
|
280
|
+
loadSettings().then(saved => {
|
|
281
|
+
if (cancelled)
|
|
282
|
+
return;
|
|
283
|
+
if (saved.isDark != null) {
|
|
284
|
+
setIsDark(saved.isDark);
|
|
285
|
+
toggleGlobalTheme(saved.isDark);
|
|
286
|
+
}
|
|
287
|
+
if (saved.modalHeightPercent != null)
|
|
288
|
+
setModalHeightPercent(saved.modalHeightPercent);
|
|
289
|
+
if (saved.tabVisibility)
|
|
290
|
+
setTabVisibility(prev => ({
|
|
291
|
+
...prev,
|
|
292
|
+
...saved.tabVisibility,
|
|
293
|
+
apis: true, // APIs is always required
|
|
294
|
+
}));
|
|
295
|
+
if (saved.defaultTab)
|
|
296
|
+
setDefaultTab(saved.defaultTab);
|
|
297
|
+
if (saved.maxNetworkLogs != null)
|
|
298
|
+
setMaxNetworkLogs(saved.maxNetworkLogs);
|
|
299
|
+
if (saved.maxConsoleLogs != null)
|
|
300
|
+
setMaxConsoleLogs(saved.maxConsoleLogs);
|
|
301
|
+
if (saved.showConsoleLevels)
|
|
302
|
+
setShowConsoleLevels(saved.showConsoleLevels);
|
|
303
|
+
if (saved.webViewCaptureCssJs != null)
|
|
304
|
+
setWebViewCaptureCssJs(saved.webViewCaptureCssJs);
|
|
305
|
+
if (saved.reduxAutoRefresh != null)
|
|
306
|
+
setReduxAutoRefreshState(saved.reduxAutoRefresh);
|
|
307
|
+
if (saved.reduxExpandDepth != null)
|
|
308
|
+
setReduxExpandDepth(saved.reduxExpandDepth);
|
|
309
|
+
if (saved.slowRequestThreshold != null)
|
|
310
|
+
setSlowRequestThreshold(saved.slowRequestThreshold);
|
|
311
|
+
if (saved.insightsShowConsoleAlerts != null)
|
|
312
|
+
setInsightsShowConsoleAlerts(saved.insightsShowConsoleAlerts);
|
|
313
|
+
if (saved.showDuplicateLogs != null)
|
|
314
|
+
setShowDuplicateLogs(saved.showDuplicateLogs);
|
|
315
|
+
if (saved.defaultTab) {
|
|
316
|
+
const dt = saved.defaultTab;
|
|
317
|
+
const vis = {
|
|
318
|
+
...{
|
|
319
|
+
insights: true,
|
|
320
|
+
apis: true,
|
|
321
|
+
logs: true,
|
|
322
|
+
analytics: false,
|
|
323
|
+
webview: false,
|
|
324
|
+
redux: false,
|
|
325
|
+
},
|
|
326
|
+
...(saved.tabVisibility || {}),
|
|
327
|
+
apis: true,
|
|
328
|
+
};
|
|
329
|
+
setActiveTab(vis[dt] ? dt : 'apis');
|
|
330
|
+
}
|
|
331
|
+
settingsHydratedRef.current = true;
|
|
332
|
+
});
|
|
333
|
+
return () => {
|
|
334
|
+
cancelled = true;
|
|
335
|
+
};
|
|
336
|
+
}, []);
|
|
337
|
+
useEffect(() => {
|
|
338
|
+
if (!settingsHydratedRef.current)
|
|
339
|
+
return;
|
|
340
|
+
saveSettings({
|
|
341
|
+
isDark,
|
|
342
|
+
modalHeightPercent,
|
|
343
|
+
tabVisibility,
|
|
344
|
+
defaultTab,
|
|
345
|
+
maxNetworkLogs,
|
|
346
|
+
maxConsoleLogs,
|
|
347
|
+
showConsoleLevels,
|
|
348
|
+
webViewCaptureCssJs,
|
|
349
|
+
reduxAutoRefresh,
|
|
350
|
+
reduxExpandDepth,
|
|
351
|
+
slowRequestThreshold,
|
|
352
|
+
insightsShowConsoleAlerts,
|
|
353
|
+
showDuplicateLogs,
|
|
354
|
+
});
|
|
355
|
+
}, [
|
|
356
|
+
isDark,
|
|
357
|
+
modalHeightPercent,
|
|
358
|
+
tabVisibility,
|
|
359
|
+
defaultTab,
|
|
360
|
+
maxNetworkLogs,
|
|
361
|
+
maxConsoleLogs,
|
|
362
|
+
showConsoleLevels,
|
|
363
|
+
webViewCaptureCssJs,
|
|
364
|
+
reduxAutoRefresh,
|
|
365
|
+
reduxExpandDepth,
|
|
366
|
+
slowRequestThreshold,
|
|
367
|
+
insightsShowConsoleAlerts,
|
|
368
|
+
showDuplicateLogs,
|
|
369
|
+
]);
|
|
370
|
+
// #1 — check NPM for a newer published version; surfaces an animated dot
|
|
371
|
+
// in the header next to the npm chip when an update is available.
|
|
372
|
+
const [latestNpmVersion, setLatestNpmVersion] = useState(null);
|
|
373
|
+
const updateAvailable = useMemo(() => {
|
|
374
|
+
if (!latestNpmVersion)
|
|
375
|
+
return false;
|
|
376
|
+
const parse = (v) => v
|
|
377
|
+
.replace(/^v/, '')
|
|
378
|
+
.split('.')
|
|
379
|
+
.map(n => parseInt(n, 10) || 0);
|
|
380
|
+
const cur = parse(LIB_VERSION);
|
|
381
|
+
const latest = parse(latestNpmVersion);
|
|
382
|
+
for (let i = 0; i < 3; i++) {
|
|
383
|
+
if ((latest[i] || 0) > (cur[i] || 0))
|
|
384
|
+
return true;
|
|
385
|
+
if ((latest[i] || 0) < (cur[i] || 0))
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
return false;
|
|
389
|
+
}, [latestNpmVersion]);
|
|
390
|
+
useEffect(() => {
|
|
391
|
+
let cancelled = false;
|
|
392
|
+
fetch('https://registry.npmjs.org/react-native-inapp-inspector/latest')
|
|
393
|
+
.then(res => (res.ok ? res.json() : null))
|
|
394
|
+
.then(data => {
|
|
395
|
+
if (!cancelled && data && typeof data.version === 'string') {
|
|
396
|
+
setLatestNpmVersion(data.version);
|
|
397
|
+
}
|
|
398
|
+
})
|
|
399
|
+
.catch(() => {
|
|
400
|
+
// Offline / blocked — silently skip the update check.
|
|
401
|
+
});
|
|
402
|
+
return () => {
|
|
403
|
+
cancelled = true;
|
|
404
|
+
};
|
|
405
|
+
}, []);
|
|
240
406
|
useEffect(() => {
|
|
241
407
|
setReduxAutoRefresh(reduxAutoRefresh);
|
|
242
408
|
}, [reduxAutoRefresh]);
|
|
@@ -250,6 +416,10 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
250
416
|
animateNextLayout();
|
|
251
417
|
setActiveTab('apis');
|
|
252
418
|
}
|
|
419
|
+
// #6 — a hidden module can't be the default landing tab.
|
|
420
|
+
if (!nextVal && defaultTab === key) {
|
|
421
|
+
setDefaultTab('apis');
|
|
422
|
+
}
|
|
253
423
|
return newVisibility;
|
|
254
424
|
});
|
|
255
425
|
};
|
|
@@ -331,6 +501,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
331
501
|
const badgeAnim = useRef(new Animated.Value(1)).current;
|
|
332
502
|
const activePulseAnim = useRef(new Animated.Value(0.4)).current;
|
|
333
503
|
const unreadPulseAnim = useRef(new Animated.Value(1)).current;
|
|
504
|
+
// #4 — diagonal light streak sweeping across the floating launcher
|
|
505
|
+
const fabShineAnim = useRef(new Animated.Value(0)).current;
|
|
334
506
|
// #11 — header "clear all" icon spin/scale animation
|
|
335
507
|
const clearAnim = useRef(new Animated.Value(0)).current;
|
|
336
508
|
// #4 — draggable floating launcher (drag anywhere on screen)
|
|
@@ -373,9 +545,9 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
373
545
|
fabDraggedRef.current = false;
|
|
374
546
|
},
|
|
375
547
|
})).current;
|
|
376
|
-
// #
|
|
548
|
+
// #2 — scroll-to-top button for the main APIs list, always visible at the
|
|
549
|
+
// bottom right of the list.
|
|
377
550
|
const apisListRef = useRef(null);
|
|
378
|
-
const [showScrollTop, setShowScrollTop] = useState(false);
|
|
379
551
|
const runClearAllWithAnimation = useCallback(() => {
|
|
380
552
|
Animated.sequence([
|
|
381
553
|
Animated.timing(clearAnim, {
|
|
@@ -412,6 +584,24 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
412
584
|
loop.start();
|
|
413
585
|
return () => loop.stop();
|
|
414
586
|
}, [pulseAnim]);
|
|
587
|
+
// #4 — sweep the shine streak across the launcher, pause, repeat.
|
|
588
|
+
useEffect(() => {
|
|
589
|
+
const loop = Animated.loop(Animated.sequence([
|
|
590
|
+
Animated.timing(fabShineAnim, {
|
|
591
|
+
toValue: 1,
|
|
592
|
+
duration: 1100,
|
|
593
|
+
useNativeDriver: true,
|
|
594
|
+
}),
|
|
595
|
+
Animated.delay(1600),
|
|
596
|
+
Animated.timing(fabShineAnim, {
|
|
597
|
+
toValue: 0,
|
|
598
|
+
duration: 0,
|
|
599
|
+
useNativeDriver: true,
|
|
600
|
+
}),
|
|
601
|
+
]));
|
|
602
|
+
loop.start();
|
|
603
|
+
return () => loop.stop();
|
|
604
|
+
}, [fabShineAnim]);
|
|
415
605
|
useEffect(() => {
|
|
416
606
|
const loop = Animated.loop(Animated.sequence([
|
|
417
607
|
Animated.timing(activePulseAnim, {
|
|
@@ -455,6 +645,16 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
455
645
|
}).start();
|
|
456
646
|
}
|
|
457
647
|
}, [newLogIds]);
|
|
648
|
+
// #6 — every time the inspector is opened, land on the chosen default tab.
|
|
649
|
+
useEffect(() => {
|
|
650
|
+
if (visible) {
|
|
651
|
+
const target = defaultTab === 'apis' || tabVisibility?.[defaultTab]
|
|
652
|
+
? defaultTab
|
|
653
|
+
: 'apis';
|
|
654
|
+
setActiveTab(target);
|
|
655
|
+
}
|
|
656
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
657
|
+
}, [visible]);
|
|
458
658
|
useEffect(() => {
|
|
459
659
|
if (visible) {
|
|
460
660
|
const task = InteractionManager.runAfterInteractions(() => {
|
|
@@ -608,8 +808,38 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
608
808
|
if (sortOrder === 'oldest') {
|
|
609
809
|
result = [...result].reverse();
|
|
610
810
|
}
|
|
811
|
+
// #9 — collapse consecutive identical requests (same method + url +
|
|
812
|
+
// status) into one row carrying a ×N counter, unless the user opted in
|
|
813
|
+
// to seeing every duplicate via Settings → "Show Duplicate Logs".
|
|
814
|
+
if (!showDuplicateLogs) {
|
|
815
|
+
const collapsed = [];
|
|
816
|
+
for (const log of result) {
|
|
817
|
+
const last = collapsed[collapsed.length - 1];
|
|
818
|
+
if (last &&
|
|
819
|
+
last.method === log.method &&
|
|
820
|
+
last.url === log.url &&
|
|
821
|
+
last.status === log.status) {
|
|
822
|
+
collapsed[collapsed.length - 1] = {
|
|
823
|
+
...last,
|
|
824
|
+
duplicateCount: (last.duplicateCount || 1) + 1,
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
collapsed.push({ ...log, duplicateCount: 1 });
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
result = collapsed;
|
|
832
|
+
}
|
|
611
833
|
return result.slice(0, maxNetworkLogs);
|
|
612
|
-
}, [
|
|
834
|
+
}, [
|
|
835
|
+
logs,
|
|
836
|
+
search,
|
|
837
|
+
statusFilters,
|
|
838
|
+
methodFilters,
|
|
839
|
+
sortOrder,
|
|
840
|
+
maxNetworkLogs,
|
|
841
|
+
showDuplicateLogs,
|
|
842
|
+
]);
|
|
613
843
|
const availableMethods = useMemo(() => {
|
|
614
844
|
const methods = new Set();
|
|
615
845
|
logs.forEach(log => {
|
|
@@ -819,8 +1049,35 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
819
1049
|
result = [...result].sort((a, b) => logSortOrder === 'newest'
|
|
820
1050
|
? b.timestamp - a.timestamp
|
|
821
1051
|
: a.timestamp - b.timestamp);
|
|
1052
|
+
// #9 — collapse consecutive identical messages into one row with a ×N
|
|
1053
|
+
// counter unless duplicates are explicitly enabled in Settings.
|
|
1054
|
+
if (!showDuplicateLogs) {
|
|
1055
|
+
const collapsed = [];
|
|
1056
|
+
for (const log of result) {
|
|
1057
|
+
const last = collapsed[collapsed.length - 1];
|
|
1058
|
+
if (last &&
|
|
1059
|
+
last.type === log.type &&
|
|
1060
|
+
last.sourceMethod === log.sourceMethod &&
|
|
1061
|
+
last.message === log.message) {
|
|
1062
|
+
collapsed[collapsed.length - 1] = {
|
|
1063
|
+
...last,
|
|
1064
|
+
duplicateCount: (last.duplicateCount || 1) + 1,
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
else {
|
|
1068
|
+
collapsed.push({ ...log, duplicateCount: 1 });
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
result = collapsed;
|
|
1072
|
+
}
|
|
822
1073
|
return result;
|
|
823
|
-
}, [
|
|
1074
|
+
}, [
|
|
1075
|
+
visibleConsoleLogs,
|
|
1076
|
+
logFilters,
|
|
1077
|
+
logSearch,
|
|
1078
|
+
logSortOrder,
|
|
1079
|
+
showDuplicateLogs,
|
|
1080
|
+
]);
|
|
824
1081
|
const filteredWebViewLogs = useMemo(() => {
|
|
825
1082
|
let result = webViewLogs;
|
|
826
1083
|
if (webViewSearch) {
|
|
@@ -969,7 +1226,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
969
1226
|
else {
|
|
970
1227
|
Alert.alert('Clear Logs', 'Are you sure you want to clear all network logs?', [
|
|
971
1228
|
{ text: 'Cancel', style: 'cancel' },
|
|
972
|
-
{
|
|
1229
|
+
{
|
|
1230
|
+
text: 'Clear All',
|
|
1231
|
+
onPress: clearNetworkOnly,
|
|
1232
|
+
style: 'destructive',
|
|
1233
|
+
},
|
|
973
1234
|
]);
|
|
974
1235
|
}
|
|
975
1236
|
}
|
|
@@ -1057,7 +1318,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1057
1318
|
return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
|
|
1058
1319
|
{/* Settings Header with back button */}
|
|
1059
1320
|
<LinearGradient colors={[AppColors.purple, '#6B4EFF']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.headerGradient}>
|
|
1060
|
-
<
|
|
1321
|
+
<SafeAreaView style={{ width: '100%' }}>
|
|
1322
|
+
<View style={[styles.header, { paddingHorizontal: 16, gap: 12 }]}>
|
|
1061
1323
|
<TouchableScale onPress={() => {
|
|
1062
1324
|
animateNextLayout();
|
|
1063
1325
|
setSettingsPage(null);
|
|
@@ -1105,7 +1367,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1105
1367
|
</Text>
|
|
1106
1368
|
</View>
|
|
1107
1369
|
</View>
|
|
1108
|
-
</
|
|
1370
|
+
</SafeAreaView>
|
|
1371
|
+
</LinearGradient>
|
|
1109
1372
|
|
|
1110
1373
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
|
|
1111
1374
|
{/* Tab list */}
|
|
@@ -1150,7 +1413,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1150
1413
|
</View>
|
|
1151
1414
|
|
|
1152
1415
|
{settingsTabs.map((tab, idx) => {
|
|
1153
|
-
const isVisible = tab.key === 'apis' || tabVisibility[tab.key];
|
|
1416
|
+
const isVisible = tab.key === 'apis' || tabVisibility?.[tab.key];
|
|
1154
1417
|
const isLast = idx === settingsTabs.length - 1;
|
|
1155
1418
|
const isLocked = tab.key === 'apis';
|
|
1156
1419
|
return (<View key={tab.key} style={{
|
|
@@ -1213,7 +1476,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1213
1476
|
}}>
|
|
1214
1477
|
{tab.label}
|
|
1215
1478
|
</Text>
|
|
1216
|
-
{
|
|
1479
|
+
{/* #6 — badge marks the configured default tab */}
|
|
1480
|
+
{tab.key === defaultTab && (<View style={{
|
|
1217
1481
|
flexDirection: 'row',
|
|
1218
1482
|
alignItems: 'center',
|
|
1219
1483
|
backgroundColor: 'rgba(104,75,155,0.08)',
|
|
@@ -1481,73 +1745,316 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1481
1745
|
})}
|
|
1482
1746
|
</View>
|
|
1483
1747
|
</View>
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
borderRadius: 10,
|
|
1506
|
-
backgroundColor: AppColors.purpleShade50,
|
|
1507
|
-
borderWidth: 1,
|
|
1508
|
-
borderColor: 'rgba(104,75,155,0.2)',
|
|
1509
|
-
alignItems: 'center',
|
|
1510
|
-
justifyContent: 'center',
|
|
1511
|
-
}}>
|
|
1512
|
-
<WhiteBackNavigation color={AppColors.purple} size={16}/>
|
|
1513
|
-
</TouchableScale>
|
|
1514
|
-
{icon && (<View style={{
|
|
1515
|
-
width: 36,
|
|
1516
|
-
height: 36,
|
|
1517
|
-
borderRadius: 10,
|
|
1748
|
+
|
|
1749
|
+
{/* Divider */}
|
|
1750
|
+
<View style={{
|
|
1751
|
+
height: 1,
|
|
1752
|
+
backgroundColor: AppColors.dividerColor,
|
|
1753
|
+
}}/>
|
|
1754
|
+
|
|
1755
|
+
{/* #6 — Default Tab */}
|
|
1756
|
+
<View style={{
|
|
1757
|
+
paddingVertical: 12,
|
|
1758
|
+
paddingHorizontal: 14,
|
|
1759
|
+
}}>
|
|
1760
|
+
<View style={{
|
|
1761
|
+
flexDirection: 'row',
|
|
1762
|
+
alignItems: 'center',
|
|
1763
|
+
gap: 8,
|
|
1764
|
+
}}>
|
|
1765
|
+
<View style={{
|
|
1766
|
+
width: 20,
|
|
1767
|
+
height: 20,
|
|
1768
|
+
borderRadius: 6,
|
|
1518
1769
|
backgroundColor: AppColors.purpleShade50,
|
|
1519
1770
|
borderWidth: 1,
|
|
1520
1771
|
borderColor: 'rgba(104,75,155,0.2)',
|
|
1521
1772
|
alignItems: 'center',
|
|
1522
1773
|
justifyContent: 'center',
|
|
1523
1774
|
}}>
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1775
|
+
<LayersIcon color={AppColors.purple} size={11}/>
|
|
1776
|
+
</View>
|
|
1777
|
+
<View style={{ flex: 1 }}>
|
|
1778
|
+
<Text style={{
|
|
1779
|
+
fontFamily: AppFonts.interBold,
|
|
1780
|
+
fontSize: 13,
|
|
1781
|
+
color: AppColors.primaryBlack,
|
|
1782
|
+
}}>
|
|
1783
|
+
Default Tab
|
|
1784
|
+
</Text>
|
|
1785
|
+
<Text style={{
|
|
1786
|
+
fontFamily: AppFonts.interRegular,
|
|
1787
|
+
fontSize: 11,
|
|
1788
|
+
color: AppColors.grayText,
|
|
1789
|
+
marginTop: 1,
|
|
1790
|
+
}}>
|
|
1791
|
+
Tab shown when the inspector opens
|
|
1792
|
+
</Text>
|
|
1793
|
+
</View>
|
|
1794
|
+
</View>
|
|
1795
|
+
|
|
1796
|
+
{/* Grid of Default Tab Cards */}
|
|
1797
|
+
<View style={{
|
|
1798
|
+
flexDirection: 'row',
|
|
1799
|
+
flexWrap: 'wrap',
|
|
1800
|
+
gap: 8,
|
|
1801
|
+
marginTop: 12,
|
|
1802
|
+
}}>
|
|
1803
|
+
{settingsTabs
|
|
1804
|
+
.filter(tab => tab.key === 'apis' || tabVisibility?.[tab.key])
|
|
1805
|
+
.map(tab => {
|
|
1806
|
+
const isActive = defaultTab === tab.key;
|
|
1807
|
+
return (<TouchableScale key={tab.key} onPress={() => setDefaultTab(tab.key)} style={{
|
|
1808
|
+
flexDirection: 'row',
|
|
1809
|
+
alignItems: 'center',
|
|
1810
|
+
gap: 8,
|
|
1811
|
+
paddingVertical: 10,
|
|
1812
|
+
paddingHorizontal: 12,
|
|
1813
|
+
borderRadius: 10,
|
|
1814
|
+
borderWidth: 1.5,
|
|
1815
|
+
borderColor: isActive ? AppColors.purple : AppColors.grayBorderSecondary,
|
|
1816
|
+
backgroundColor: isActive ? 'rgba(104,75,155,0.06)' : AppColors.primaryLight,
|
|
1817
|
+
minWidth: '47%',
|
|
1818
|
+
flex: 1,
|
|
1819
|
+
}}>
|
|
1820
|
+
<View style={{
|
|
1821
|
+
width: 22,
|
|
1822
|
+
height: 22,
|
|
1823
|
+
borderRadius: 6,
|
|
1824
|
+
backgroundColor: isActive ? AppColors.purple : AppColors.purpleShade50,
|
|
1825
|
+
alignItems: 'center',
|
|
1826
|
+
justifyContent: 'center',
|
|
1827
|
+
}}>
|
|
1828
|
+
{tab.icon === 'insights' && (<InsightsIcon color={isActive ? '#FFFFFF' : AppColors.purple} size={11}/>)}
|
|
1829
|
+
{tab.icon === 'apis' && (<SignalIcon color={isActive ? '#FFFFFF' : AppColors.purple} size={11}/>)}
|
|
1830
|
+
{tab.icon === 'logs' && (<TerminalIcon color={isActive ? '#FFFFFF' : AppColors.purple} size={11}/>)}
|
|
1831
|
+
{tab.icon === 'analytics' && (<AnalyticsIcon color={isActive ? '#FFFFFF' : AppColors.purple} size={11}/>)}
|
|
1832
|
+
{tab.icon === 'webview' && (<GlobeIcon color={isActive ? '#FFFFFF' : AppColors.purple} size={11}/>)}
|
|
1833
|
+
{tab.icon === 'redux' && (<TerminalIcon color={isActive ? '#FFFFFF' : AppColors.purple} size={11}/>)}
|
|
1834
|
+
</View>
|
|
1835
|
+
<Text style={{
|
|
1836
|
+
fontFamily: AppFonts.interBold,
|
|
1837
|
+
fontSize: 13,
|
|
1838
|
+
color: isActive ? AppColors.purple : AppColors.primaryBlack,
|
|
1839
|
+
flex: 1,
|
|
1840
|
+
}}>
|
|
1841
|
+
{tab.label}
|
|
1842
|
+
</Text>
|
|
1843
|
+
{isActive && (<View style={{
|
|
1844
|
+
width: 14,
|
|
1845
|
+
height: 14,
|
|
1846
|
+
borderRadius: 7,
|
|
1847
|
+
backgroundColor: AppColors.purple,
|
|
1848
|
+
alignItems: 'center',
|
|
1849
|
+
justifyContent: 'center',
|
|
1850
|
+
}}>
|
|
1851
|
+
<CheckIcon size={8} color="#FFFFFF"/>
|
|
1852
|
+
</View>)}
|
|
1853
|
+
</TouchableScale>);
|
|
1854
|
+
})}
|
|
1855
|
+
</View>
|
|
1856
|
+
</View>
|
|
1857
|
+
|
|
1858
|
+
{/* Divider */}
|
|
1859
|
+
<View style={{
|
|
1860
|
+
height: 1,
|
|
1861
|
+
backgroundColor: AppColors.dividerColor,
|
|
1862
|
+
}}/>
|
|
1863
|
+
|
|
1864
|
+
{/* #9 — Show Duplicate Logs */}
|
|
1865
|
+
<View style={{
|
|
1866
|
+
flexDirection: 'row',
|
|
1867
|
+
alignItems: 'center',
|
|
1868
|
+
paddingVertical: 12,
|
|
1869
|
+
paddingHorizontal: 14,
|
|
1870
|
+
gap: 12,
|
|
1871
|
+
}}>
|
|
1872
|
+
<View style={{
|
|
1873
|
+
flex: 1,
|
|
1874
|
+
flexDirection: 'row',
|
|
1875
|
+
alignItems: 'center',
|
|
1876
|
+
gap: 8,
|
|
1877
|
+
}}>
|
|
1878
|
+
<View style={{
|
|
1879
|
+
width: 20,
|
|
1880
|
+
height: 20,
|
|
1881
|
+
borderRadius: 6,
|
|
1882
|
+
backgroundColor: AppColors.purpleShade50,
|
|
1883
|
+
borderWidth: 1,
|
|
1884
|
+
borderColor: 'rgba(104,75,155,0.2)',
|
|
1885
|
+
alignItems: 'center',
|
|
1886
|
+
justifyContent: 'center',
|
|
1887
|
+
}}>
|
|
1888
|
+
<EyeIcon color={AppColors.purple} size={11}/>
|
|
1889
|
+
</View>
|
|
1890
|
+
<View style={{ flex: 1 }}>
|
|
1891
|
+
<Text style={{
|
|
1892
|
+
fontFamily: AppFonts.interBold,
|
|
1893
|
+
fontSize: 13,
|
|
1894
|
+
color: AppColors.primaryBlack,
|
|
1895
|
+
}}>
|
|
1896
|
+
Show Duplicate Logs
|
|
1897
|
+
</Text>
|
|
1898
|
+
<Text style={{
|
|
1899
|
+
fontFamily: AppFonts.interRegular,
|
|
1900
|
+
fontSize: 11,
|
|
1901
|
+
color: AppColors.grayText,
|
|
1902
|
+
marginTop: 1,
|
|
1903
|
+
}}>
|
|
1904
|
+
Off: repeated identical entries collapse into one row
|
|
1905
|
+
with a ×N count
|
|
1906
|
+
</Text>
|
|
1907
|
+
</View>
|
|
1908
|
+
</View>
|
|
1909
|
+
|
|
1910
|
+
{/* Toggle Switch */}
|
|
1911
|
+
<TouchableScale onPress={() => setShowDuplicateLogs(prev => !prev)} style={{
|
|
1912
|
+
width: 38,
|
|
1913
|
+
height: 22,
|
|
1914
|
+
borderRadius: 11,
|
|
1915
|
+
backgroundColor: showDuplicateLogs
|
|
1916
|
+
? AppColors.purple
|
|
1917
|
+
: AppColors.grayBorderSecondary,
|
|
1918
|
+
padding: 2,
|
|
1919
|
+
justifyContent: 'center',
|
|
1920
|
+
alignItems: showDuplicateLogs ? 'flex-end' : 'flex-start',
|
|
1921
|
+
}}>
|
|
1922
|
+
<View style={{
|
|
1923
|
+
width: 18,
|
|
1924
|
+
height: 18,
|
|
1925
|
+
borderRadius: 9,
|
|
1926
|
+
backgroundColor: '#FFFFFF',
|
|
1927
|
+
shadowColor: '#000',
|
|
1928
|
+
shadowOpacity: 0.15,
|
|
1929
|
+
shadowRadius: 1.5,
|
|
1930
|
+
shadowOffset: { width: 0, height: 1 },
|
|
1931
|
+
}}/>
|
|
1932
|
+
</TouchableScale>
|
|
1933
|
+
</View>
|
|
1934
|
+
|
|
1935
|
+
{/* Divider */}
|
|
1936
|
+
<View style={{
|
|
1937
|
+
height: 1,
|
|
1938
|
+
backgroundColor: AppColors.dividerColor,
|
|
1939
|
+
}}/>
|
|
1940
|
+
|
|
1941
|
+
{/* Reset Settings */}
|
|
1942
|
+
<View style={{
|
|
1943
|
+
flexDirection: 'row',
|
|
1944
|
+
alignItems: 'center',
|
|
1945
|
+
paddingVertical: 12,
|
|
1946
|
+
paddingHorizontal: 14,
|
|
1947
|
+
gap: 12,
|
|
1948
|
+
}}>
|
|
1949
|
+
<View style={{
|
|
1950
|
+
flex: 1,
|
|
1951
|
+
flexDirection: 'row',
|
|
1952
|
+
alignItems: 'center',
|
|
1953
|
+
gap: 8,
|
|
1954
|
+
}}>
|
|
1955
|
+
<View style={{
|
|
1956
|
+
width: 20,
|
|
1957
|
+
height: 20,
|
|
1958
|
+
borderRadius: 6,
|
|
1959
|
+
backgroundColor: 'rgba(239,68,68,0.08)',
|
|
1960
|
+
borderWidth: 1,
|
|
1961
|
+
borderColor: 'rgba(239,68,68,0.2)',
|
|
1962
|
+
alignItems: 'center',
|
|
1963
|
+
justifyContent: 'center',
|
|
1964
|
+
}}>
|
|
1965
|
+
<TrashIcon color={AppColors.errorColor} size={11}/>
|
|
1966
|
+
</View>
|
|
1967
|
+
<View style={{ flex: 1 }}>
|
|
1968
|
+
<Text style={{
|
|
1969
|
+
fontFamily: AppFonts.interBold,
|
|
1970
|
+
fontSize: 13,
|
|
1971
|
+
color: AppColors.primaryBlack,
|
|
1972
|
+
}}>
|
|
1973
|
+
Reset Settings
|
|
1974
|
+
</Text>
|
|
1975
|
+
<Text style={{
|
|
1976
|
+
fontFamily: AppFonts.interRegular,
|
|
1977
|
+
fontSize: 11,
|
|
1978
|
+
color: AppColors.grayText,
|
|
1979
|
+
marginTop: 1,
|
|
1980
|
+
}}>
|
|
1981
|
+
Wipe custom configurations and load package defaults
|
|
1982
|
+
</Text>
|
|
1983
|
+
</View>
|
|
1984
|
+
</View>
|
|
1985
|
+
|
|
1986
|
+
<TouchableScale onPress={resetToDefaults} style={{
|
|
1536
1987
|
paddingHorizontal: 10,
|
|
1537
1988
|
paddingVertical: 5,
|
|
1538
|
-
borderRadius:
|
|
1989
|
+
borderRadius: 7,
|
|
1990
|
+
backgroundColor: 'rgba(255,46,87,0.08)',
|
|
1539
1991
|
borderWidth: 1,
|
|
1540
|
-
borderColor: 'rgba(
|
|
1992
|
+
borderColor: 'rgba(255,46,87,0.2)',
|
|
1541
1993
|
}}>
|
|
1542
|
-
|
|
1994
|
+
<Text style={{
|
|
1543
1995
|
fontFamily: AppFonts.interBold,
|
|
1544
1996
|
fontSize: 11,
|
|
1545
|
-
color: AppColors.
|
|
1997
|
+
color: AppColors.errorColor,
|
|
1546
1998
|
}}>
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1999
|
+
Reset
|
|
2000
|
+
</Text>
|
|
2001
|
+
</TouchableScale>
|
|
2002
|
+
</View>
|
|
2003
|
+
</View>
|
|
2004
|
+
</View>
|
|
2005
|
+
|
|
2006
|
+
{/* Storage Status */}
|
|
2007
|
+
<View style={{
|
|
2008
|
+
backgroundColor: isPersistentStorageAvailable()
|
|
2009
|
+
? 'rgba(74,222,128,0.08)'
|
|
2010
|
+
: 'rgba(234,179,8,0.08)',
|
|
2011
|
+
borderRadius: 12,
|
|
2012
|
+
borderWidth: 1,
|
|
2013
|
+
borderColor: isPersistentStorageAvailable()
|
|
2014
|
+
? 'rgba(74,222,128,0.2)'
|
|
2015
|
+
: 'rgba(234,179,8,0.2)',
|
|
2016
|
+
padding: 12,
|
|
2017
|
+
marginTop: 16,
|
|
2018
|
+
flexDirection: 'row',
|
|
2019
|
+
alignItems: 'center',
|
|
2020
|
+
gap: 10,
|
|
2021
|
+
}}>
|
|
2022
|
+
<View style={{
|
|
2023
|
+
width: 8,
|
|
2024
|
+
height: 8,
|
|
2025
|
+
borderRadius: 4,
|
|
2026
|
+
backgroundColor: isPersistentStorageAvailable() ? '#22C55E' : '#EAB308',
|
|
2027
|
+
}}/>
|
|
2028
|
+
<View style={{ flex: 1 }}>
|
|
2029
|
+
<Text style={{
|
|
2030
|
+
fontFamily: AppFonts.interBold,
|
|
2031
|
+
fontSize: 12,
|
|
2032
|
+
color: isPersistentStorageAvailable() ? '#15803D' : '#854D0E',
|
|
2033
|
+
}}>
|
|
2034
|
+
{isPersistentStorageAvailable()
|
|
2035
|
+
? `Storage: Persistent (${storage ? 'Custom' : 'iOS Settings'})`
|
|
2036
|
+
: 'Storage: Temporary (In-Memory)'}
|
|
2037
|
+
</Text>
|
|
2038
|
+
<Text style={{
|
|
2039
|
+
fontFamily: AppFonts.interRegular,
|
|
2040
|
+
fontSize: 10.5,
|
|
2041
|
+
color: isPersistentStorageAvailable() ? '#166534' : '#854D0E',
|
|
2042
|
+
marginTop: 2,
|
|
2043
|
+
opacity: 0.8,
|
|
2044
|
+
}}>
|
|
2045
|
+
{isPersistentStorageAvailable()
|
|
2046
|
+
? 'Your settings are saved across app restarts.'
|
|
2047
|
+
: 'Settings reset when closed. To persist settings, pass a storage object to <NetworkInspector storage={...} />.'}
|
|
2048
|
+
</Text>
|
|
2049
|
+
</View>
|
|
2050
|
+
</View>
|
|
2051
|
+
</ScrollView>
|
|
2052
|
+
</View>);
|
|
2053
|
+
}
|
|
2054
|
+
const goBackToMain = () => {
|
|
2055
|
+
animateNextLayout();
|
|
2056
|
+
setSettingsPage('main');
|
|
2057
|
+
};
|
|
1551
2058
|
// Helper: settings row with icon + label + optional description
|
|
1552
2059
|
const renderSettingRow = (opts) => (<View style={{
|
|
1553
2060
|
paddingVertical: 12,
|
|
@@ -1627,9 +2134,15 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1627
2134
|
})}
|
|
1628
2135
|
</View>)}
|
|
1629
2136
|
</View>);
|
|
2137
|
+
let content = null;
|
|
2138
|
+
let title = '';
|
|
2139
|
+
let icon = null;
|
|
2140
|
+
let rightInfo = '';
|
|
1630
2141
|
if (settingsPage === 'apis') {
|
|
1631
|
-
|
|
1632
|
-
|
|
2142
|
+
title = 'APIs Settings';
|
|
2143
|
+
icon = <SignalIcon color="#FFFFFF" size={16}/>;
|
|
2144
|
+
rightInfo = `Total: ${logs.length}`;
|
|
2145
|
+
content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
|
|
1633
2146
|
<View style={{
|
|
1634
2147
|
backgroundColor: AppColors.primaryLight,
|
|
1635
2148
|
padding: 16,
|
|
@@ -1689,9 +2202,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1689
2202
|
</View>
|
|
1690
2203
|
</ScrollView>);
|
|
1691
2204
|
}
|
|
1692
|
-
if (settingsPage === 'logs') {
|
|
1693
|
-
|
|
1694
|
-
|
|
2205
|
+
else if (settingsPage === 'logs') {
|
|
2206
|
+
title = 'Logs Settings';
|
|
2207
|
+
icon = <TerminalIcon color="#FFFFFF" size={16}/>;
|
|
2208
|
+
rightInfo = `Total: ${consoleLogs.length}`;
|
|
2209
|
+
content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
|
|
1695
2210
|
<View style={{
|
|
1696
2211
|
backgroundColor: AppColors.primaryLight,
|
|
1697
2212
|
padding: 16,
|
|
@@ -1720,7 +2235,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1720
2235
|
Log Levels
|
|
1721
2236
|
</Text>
|
|
1722
2237
|
{['info', 'warn', 'error'].map((level, li) => {
|
|
1723
|
-
const isLvlActive = showConsoleLevels[level];
|
|
2238
|
+
const isLvlActive = showConsoleLevels?.[level];
|
|
1724
2239
|
const levelColor = level === 'error'
|
|
1725
2240
|
? AppColors.errorColor
|
|
1726
2241
|
: level === 'warn'
|
|
@@ -1801,9 +2316,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1801
2316
|
</View>
|
|
1802
2317
|
</ScrollView>);
|
|
1803
2318
|
}
|
|
1804
|
-
if (settingsPage === 'analytics') {
|
|
1805
|
-
|
|
1806
|
-
|
|
2319
|
+
else if (settingsPage === 'analytics') {
|
|
2320
|
+
title = 'Analytics Settings';
|
|
2321
|
+
icon = <AnalyticsIcon color="#FFFFFF" size={16}/>;
|
|
2322
|
+
rightInfo = `Events: ${analyticsEvents.length}`;
|
|
2323
|
+
content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
|
|
1807
2324
|
<View style={{
|
|
1808
2325
|
backgroundColor: AppColors.primaryLight,
|
|
1809
2326
|
padding: 16,
|
|
@@ -1857,9 +2374,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1857
2374
|
</View>
|
|
1858
2375
|
</ScrollView>);
|
|
1859
2376
|
}
|
|
1860
|
-
if (settingsPage === 'webview') {
|
|
1861
|
-
|
|
1862
|
-
|
|
2377
|
+
else if (settingsPage === 'webview') {
|
|
2378
|
+
title = 'WebView Settings';
|
|
2379
|
+
icon = <GlobeIcon color="#FFFFFF" size={16}/>;
|
|
2380
|
+
rightInfo = `History: ${webViewNavHistory.length}`;
|
|
2381
|
+
content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
|
|
1863
2382
|
<View style={{
|
|
1864
2383
|
backgroundColor: AppColors.primaryLight,
|
|
1865
2384
|
padding: 16,
|
|
@@ -1929,9 +2448,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1929
2448
|
</View>
|
|
1930
2449
|
</ScrollView>);
|
|
1931
2450
|
}
|
|
1932
|
-
if (settingsPage === 'redux') {
|
|
1933
|
-
|
|
1934
|
-
|
|
2451
|
+
else if (settingsPage === 'redux') {
|
|
2452
|
+
title = 'Redux Settings';
|
|
2453
|
+
icon = <TerminalIcon color="#FFFFFF" size={16}/>;
|
|
2454
|
+
rightInfo = `Reducers: ${Object.keys(reduxState || {}).length}`;
|
|
2455
|
+
content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
|
|
1935
2456
|
<View style={{
|
|
1936
2457
|
backgroundColor: AppColors.primaryLight,
|
|
1937
2458
|
padding: 16,
|
|
@@ -2015,53 +2536,108 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2015
2536
|
</View>
|
|
2016
2537
|
</ScrollView>);
|
|
2017
2538
|
}
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2539
|
+
else {
|
|
2540
|
+
title = 'Insights Settings';
|
|
2541
|
+
icon = <InsightsIcon color="#FFFFFF" size={16}/>;
|
|
2542
|
+
content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
|
|
2543
|
+
<View style={{
|
|
2544
|
+
backgroundColor: AppColors.primaryLight,
|
|
2545
|
+
padding: 16,
|
|
2546
|
+
borderRadius: 12,
|
|
2547
|
+
borderWidth: 1,
|
|
2548
|
+
borderColor: AppColors.grayBorderSecondary,
|
|
2549
|
+
gap: 4,
|
|
2550
|
+
}}>
|
|
2551
|
+
{renderSettingRow({
|
|
2552
|
+
icon: <SignalIcon color={AppColors.purple} size={16}/>,
|
|
2553
|
+
label: 'Slow Latency Warning',
|
|
2554
|
+
description: 'Alert threshold for slow API request duration',
|
|
2555
|
+
picker: {
|
|
2556
|
+
options: [500, 1000, 2000],
|
|
2557
|
+
selectedValue: slowRequestThreshold,
|
|
2558
|
+
onSelect: setSlowRequestThreshold,
|
|
2559
|
+
},
|
|
2560
|
+
})}
|
|
2561
|
+
<View style={{ height: 1, backgroundColor: AppColors.dividerColor }}/>
|
|
2562
|
+
{renderSettingRow({
|
|
2563
|
+
icon: <TerminalIcon color={AppColors.purple} size={16}/>,
|
|
2564
|
+
label: 'Show Console Alerts',
|
|
2565
|
+
description: 'Flags critical warnings or crash events on dashboard',
|
|
2566
|
+
isLast: true,
|
|
2567
|
+
onPress: () => setInsightsShowConsoleAlerts(prev => !prev),
|
|
2568
|
+
right: (<View style={{
|
|
2569
|
+
width: 22,
|
|
2570
|
+
height: 22,
|
|
2571
|
+
borderRadius: 6,
|
|
2572
|
+
borderWidth: 2,
|
|
2573
|
+
borderColor: insightsShowConsoleAlerts
|
|
2574
|
+
? AppColors.purple
|
|
2575
|
+
: AppColors.grayTextWeak,
|
|
2576
|
+
backgroundColor: insightsShowConsoleAlerts
|
|
2577
|
+
? 'rgba(104, 75, 155, 0.1)'
|
|
2578
|
+
: 'transparent',
|
|
2579
|
+
alignItems: 'center',
|
|
2580
|
+
justifyContent: 'center',
|
|
2581
|
+
}}>
|
|
2582
|
+
{insightsShowConsoleAlerts && (<CheckIcon size={12} color={AppColors.purple}/>)}
|
|
2583
|
+
</View>),
|
|
2584
|
+
})}
|
|
2585
|
+
</View>
|
|
2586
|
+
</ScrollView>);
|
|
2587
|
+
}
|
|
2588
|
+
return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
|
|
2589
|
+
<LinearGradient colors={[AppColors.purple, '#6B4EFF']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.headerGradient}>
|
|
2590
|
+
<SafeAreaView style={{ width: '100%' }}>
|
|
2591
|
+
<View style={[styles.header, { paddingHorizontal: 16, gap: 12 }]}>
|
|
2592
|
+
<TouchableScale onPress={goBackToMain} hitSlop={12} style={{
|
|
2593
|
+
padding: 8,
|
|
2594
|
+
borderRadius: 10,
|
|
2595
|
+
backgroundColor: 'rgba(255, 255, 255, 0.15)',
|
|
2025
2596
|
borderWidth: 1,
|
|
2026
|
-
borderColor:
|
|
2027
|
-
gap: 4,
|
|
2597
|
+
borderColor: 'rgba(255, 255, 255, 0.08)',
|
|
2028
2598
|
}}>
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2599
|
+
<WhiteBackNavigation color="#FFFFFF" size={16}/>
|
|
2600
|
+
</TouchableScale>
|
|
2601
|
+
{icon && (<View style={{
|
|
2602
|
+
width: 30,
|
|
2603
|
+
height: 30,
|
|
2604
|
+
borderRadius: 8,
|
|
2605
|
+
backgroundColor: 'rgba(255, 255, 255, 0.15)',
|
|
2606
|
+
alignItems: 'center',
|
|
2607
|
+
justifyContent: 'center',
|
|
2608
|
+
}}>
|
|
2609
|
+
{icon}
|
|
2610
|
+
</View>)}
|
|
2611
|
+
<View style={{ flex: 1 }}>
|
|
2612
|
+
<Text style={{
|
|
2613
|
+
fontFamily: AppFonts.interBold,
|
|
2614
|
+
fontSize: 17,
|
|
2615
|
+
color: '#FFFFFF',
|
|
2616
|
+
}}>
|
|
2617
|
+
{title}
|
|
2618
|
+
</Text>
|
|
2619
|
+
</View>
|
|
2620
|
+
{rightInfo ? (<View style={{
|
|
2621
|
+
backgroundColor: 'rgba(255, 255, 255, 0.15)',
|
|
2622
|
+
paddingHorizontal: 8,
|
|
2623
|
+
paddingVertical: 4,
|
|
2624
|
+
borderRadius: 8,
|
|
2625
|
+
borderWidth: 1,
|
|
2626
|
+
borderColor: 'rgba(255, 255, 255, 0.1)',
|
|
2627
|
+
}}>
|
|
2628
|
+
<Text style={{
|
|
2629
|
+
fontFamily: AppFonts.interBold,
|
|
2630
|
+
fontSize: 11,
|
|
2631
|
+
color: '#FFFFFF',
|
|
2632
|
+
}}>
|
|
2633
|
+
{rightInfo}
|
|
2634
|
+
</Text>
|
|
2635
|
+
</View>) : null}
|
|
2636
|
+
</View>
|
|
2637
|
+
</SafeAreaView>
|
|
2638
|
+
</LinearGradient>
|
|
2639
|
+
{content}
|
|
2640
|
+
</View>);
|
|
2065
2641
|
};
|
|
2066
2642
|
const renderInsightsDashboard = () => {
|
|
2067
2643
|
const apiTotal = logs.length;
|
|
@@ -2097,11 +2673,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2097
2673
|
const totalSignals = apiTotal + logTotal + analyticsTotal + webviewTotal;
|
|
2098
2674
|
const totalIssues = apiErrors + logErrors;
|
|
2099
2675
|
const activeModules = [
|
|
2100
|
-
tabVisibility
|
|
2101
|
-
tabVisibility
|
|
2102
|
-
tabVisibility
|
|
2103
|
-
tabVisibility
|
|
2104
|
-
tabVisibility
|
|
2676
|
+
tabVisibility?.apis,
|
|
2677
|
+
tabVisibility?.logs,
|
|
2678
|
+
tabVisibility?.analytics,
|
|
2679
|
+
tabVisibility?.webview,
|
|
2680
|
+
tabVisibility?.redux,
|
|
2105
2681
|
].filter(Boolean).length;
|
|
2106
2682
|
// Composite health score: success rate penalised by error volume and slow requests.
|
|
2107
2683
|
const healthScore = totalSignals === 0
|
|
@@ -2268,7 +2844,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2268
2844
|
</View>
|
|
2269
2845
|
|
|
2270
2846
|
{/* Module 1: APIs */}
|
|
2271
|
-
{tabVisibility
|
|
2847
|
+
{tabVisibility?.apis && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('apis')}>
|
|
2272
2848
|
<View style={styles.dashboardModuleHeader}>
|
|
2273
2849
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2274
2850
|
<SignalIcon color={AppColors.purple} size={18}/>
|
|
@@ -2375,7 +2951,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2375
2951
|
</View>)}
|
|
2376
2952
|
</View>
|
|
2377
2953
|
</TouchableScale>)}
|
|
2378
|
-
{tabVisibility
|
|
2954
|
+
{tabVisibility?.logs && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('logs')}>
|
|
2379
2955
|
<View style={styles.dashboardModuleHeader}>
|
|
2380
2956
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2381
2957
|
<TerminalIcon color="#0D9488" size={18}/>
|
|
@@ -2416,7 +2992,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2416
2992
|
</TouchableScale>)}
|
|
2417
2993
|
|
|
2418
2994
|
{/* Module 3: Analytics */}
|
|
2419
|
-
{tabVisibility
|
|
2995
|
+
{tabVisibility?.analytics && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('analytics')}>
|
|
2420
2996
|
<View style={styles.dashboardModuleHeader}>
|
|
2421
2997
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2422
2998
|
<AnalyticsIcon color="#EA580C" size={18}/>
|
|
@@ -2453,7 +3029,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2453
3029
|
</TouchableScale>)}
|
|
2454
3030
|
|
|
2455
3031
|
{/* Module 4: WebView */}
|
|
2456
|
-
{tabVisibility
|
|
3032
|
+
{tabVisibility?.webview && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('webview')}>
|
|
2457
3033
|
<View style={styles.dashboardModuleHeader}>
|
|
2458
3034
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2459
3035
|
<GlobeIcon color="#2563EB" size={18}/>
|
|
@@ -2486,7 +3062,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2486
3062
|
</TouchableScale>)}
|
|
2487
3063
|
|
|
2488
3064
|
{/* Module 5: Redux Store */}
|
|
2489
|
-
{tabVisibility
|
|
3065
|
+
{tabVisibility?.redux && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('redux')}>
|
|
2490
3066
|
<View style={styles.dashboardModuleHeader}>
|
|
2491
3067
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2492
3068
|
<TerminalIcon color={AppColors.purple} size={18}/>
|
|
@@ -2751,6 +3327,29 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2751
3327
|
}} hitSlop={10}>
|
|
2752
3328
|
<Animated.View style={[styles.fabPulseRing, { transform: [{ scale: pulseAnim }] }]}/>
|
|
2753
3329
|
<BrandCircleIcon size={62}/>
|
|
3330
|
+
{/* #4 — shining sweep, clipped inside the circular launcher */}
|
|
3331
|
+
<View pointerEvents="none" style={styles.fabShineClip}>
|
|
3332
|
+
<Animated.View style={[
|
|
3333
|
+
styles.fabShineStreak,
|
|
3334
|
+
{
|
|
3335
|
+
transform: [
|
|
3336
|
+
{
|
|
3337
|
+
translateX: fabShineAnim.interpolate({
|
|
3338
|
+
inputRange: [0, 1],
|
|
3339
|
+
outputRange: [-48, 96],
|
|
3340
|
+
}),
|
|
3341
|
+
},
|
|
3342
|
+
{ rotate: '25deg' },
|
|
3343
|
+
],
|
|
3344
|
+
},
|
|
3345
|
+
]}>
|
|
3346
|
+
<LinearGradient colors={[
|
|
3347
|
+
'rgba(255,255,255,0)',
|
|
3348
|
+
'rgba(255,255,255,0.55)',
|
|
3349
|
+
'rgba(255,255,255,0)',
|
|
3350
|
+
]} start={{ x: 0, y: 0.5 }} end={{ x: 1, y: 0.5 }} style={{ flex: 1 }}/>
|
|
3351
|
+
</Animated.View>
|
|
3352
|
+
</View>
|
|
2754
3353
|
{(logs.length > 0 || analyticsEvents.length > 0) && (<Animated.View style={[
|
|
2755
3354
|
styles.fabBadge,
|
|
2756
3355
|
hasErrors ? styles.fabBadgeError : styles.fabBadgeNormal,
|
|
@@ -2776,7 +3375,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2776
3375
|
<StatusBar translucent backgroundColor="transparent" barStyle="light-content"/>
|
|
2777
3376
|
|
|
2778
3377
|
<LinearGradient colors={[AppColors.purple, '#6B4EFF']} style={styles.headerGradient}>
|
|
2779
|
-
<
|
|
3378
|
+
<SafeAreaView style={{ width: '100%' }}>
|
|
3379
|
+
<View style={styles.header}>
|
|
2780
3380
|
<View style={[
|
|
2781
3381
|
styles.headerLeft,
|
|
2782
3382
|
{
|
|
@@ -2923,6 +3523,29 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2923
3523
|
</Text>
|
|
2924
3524
|
</View>
|
|
2925
3525
|
</View>
|
|
3526
|
+
|
|
3527
|
+
{/* #1 — pulsing dot when a newer version is on NPM */}
|
|
3528
|
+
{updateAvailable && (<Pressable hitSlop={10} onPress={() => Alert.alert('Update Available', `react-native-inapp-inspector v${latestNpmVersion} is available on NPM (installed: v${LIB_VERSION}).`, [
|
|
3529
|
+
{ text: 'Later', style: 'cancel' },
|
|
3530
|
+
{
|
|
3531
|
+
text: 'View on NPM',
|
|
3532
|
+
onPress: () => Linking.openURL('https://www.npmjs.com/package/react-native-inapp-inspector').catch(() => { }),
|
|
3533
|
+
},
|
|
3534
|
+
])} style={{
|
|
3535
|
+
alignItems: 'center',
|
|
3536
|
+
justifyContent: 'center',
|
|
3537
|
+
}}>
|
|
3538
|
+
<Animated.View style={{
|
|
3539
|
+
width: 8,
|
|
3540
|
+
height: 8,
|
|
3541
|
+
borderRadius: 4,
|
|
3542
|
+
backgroundColor: '#4ADE80',
|
|
3543
|
+
borderWidth: 1,
|
|
3544
|
+
borderColor: 'rgba(255,255,255,0.9)',
|
|
3545
|
+
opacity: activePulseAnim,
|
|
3546
|
+
transform: [{ scale: unreadPulseAnim }],
|
|
3547
|
+
}}/>
|
|
3548
|
+
</Pressable>)}
|
|
2926
3549
|
</View>
|
|
2927
3550
|
</View>
|
|
2928
3551
|
</View>) : null}
|
|
@@ -3071,7 +3694,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3071
3694
|
},
|
|
3072
3695
|
],
|
|
3073
3696
|
}}>
|
|
3074
|
-
<
|
|
3697
|
+
<WipeIcon color="#FFFFFF" size={16}/>
|
|
3075
3698
|
</Animated.View>
|
|
3076
3699
|
</TouchableScale>)}
|
|
3077
3700
|
|
|
@@ -3090,7 +3713,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3090
3713
|
</TouchableScale>
|
|
3091
3714
|
</View>
|
|
3092
3715
|
</View>
|
|
3093
|
-
</
|
|
3716
|
+
</SafeAreaView>
|
|
3717
|
+
</LinearGradient>
|
|
3094
3718
|
|
|
3095
3719
|
{/* ─── Horizontal Scrollable Tab Bar inside Content ─── */}
|
|
3096
3720
|
{selected == null &&
|
|
@@ -3135,7 +3759,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3135
3759
|
icon: 'redux',
|
|
3136
3760
|
},
|
|
3137
3761
|
]
|
|
3138
|
-
.filter(tab => tabVisibility[tab.key])
|
|
3762
|
+
.filter(tab => tabVisibility?.[tab.key])
|
|
3139
3763
|
.map(tab => {
|
|
3140
3764
|
const isActive = activeTab === tab.key;
|
|
3141
3765
|
const iconColor = isActive
|
|
@@ -3251,7 +3875,16 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3251
3875
|
animateNextLayout();
|
|
3252
3876
|
setAnalyticsSubTab('ga_events');
|
|
3253
3877
|
}}>
|
|
3254
|
-
<
|
|
3878
|
+
<View style={{
|
|
3879
|
+
flexDirection: 'row',
|
|
3880
|
+
alignItems: 'center',
|
|
3881
|
+
gap: 6,
|
|
3882
|
+
}}>
|
|
3883
|
+
{/* #7 */}
|
|
3884
|
+
<AnalyticsIcon size={13} color={analyticsSubTab === 'ga_events'
|
|
3885
|
+
? AppColors.purple
|
|
3886
|
+
: AppColors.grayTextStrong}/>
|
|
3887
|
+
<Text style={[
|
|
3255
3888
|
{
|
|
3256
3889
|
fontFamily: AppFonts.interMedium,
|
|
3257
3890
|
fontSize: 13,
|
|
@@ -3262,12 +3895,13 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3262
3895
|
color: AppColors.purple,
|
|
3263
3896
|
},
|
|
3264
3897
|
]}>
|
|
3265
|
-
|
|
3266
|
-
|
|
3898
|
+
GA Events (
|
|
3899
|
+
{analyticsSearch
|
|
3267
3900
|
? filteredAnalyticsEvents.length
|
|
3268
3901
|
: analyticsEvents.length}
|
|
3269
|
-
|
|
3270
|
-
|
|
3902
|
+
)
|
|
3903
|
+
</Text>
|
|
3904
|
+
</View>
|
|
3271
3905
|
</Pressable>
|
|
3272
3906
|
<Pressable style={[
|
|
3273
3907
|
{
|
|
@@ -3288,7 +3922,16 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3288
3922
|
animateNextLayout();
|
|
3289
3923
|
setAnalyticsSubTab('top_events');
|
|
3290
3924
|
}}>
|
|
3291
|
-
<
|
|
3925
|
+
<View style={{
|
|
3926
|
+
flexDirection: 'row',
|
|
3927
|
+
alignItems: 'center',
|
|
3928
|
+
gap: 6,
|
|
3929
|
+
}}>
|
|
3930
|
+
{/* #7 */}
|
|
3931
|
+
<TrendingUpIcon size={13} color={analyticsSubTab === 'top_events'
|
|
3932
|
+
? AppColors.purple
|
|
3933
|
+
: AppColors.grayTextStrong}/>
|
|
3934
|
+
<Text style={[
|
|
3292
3935
|
{
|
|
3293
3936
|
fontFamily: AppFonts.interMedium,
|
|
3294
3937
|
fontSize: 13,
|
|
@@ -3299,8 +3942,9 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3299
3942
|
color: AppColors.purple,
|
|
3300
3943
|
},
|
|
3301
3944
|
]}>
|
|
3302
|
-
|
|
3303
|
-
|
|
3945
|
+
Top Events ({topEventsArray.length})
|
|
3946
|
+
</Text>
|
|
3947
|
+
</View>
|
|
3304
3948
|
</Pressable>
|
|
3305
3949
|
</View>
|
|
3306
3950
|
</View>)}
|
|
@@ -3410,7 +4054,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3410
4054
|
flexGrow: 1,
|
|
3411
4055
|
},
|
|
3412
4056
|
]} keyboardShouldPersistTaps="handled"/>)) : activeTab === 'apis' && selected == null ? (<View style={{ flex: 1 }}>
|
|
3413
|
-
<FlatList ref={apisListRef}
|
|
4057
|
+
<FlatList ref={apisListRef} data={groupedData} keyExtractor={item => item?.id?.toString()} renderItem={renderItem} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={true} ListHeaderComponent={<View style={{ marginTop: 8 }}>
|
|
3414
4058
|
<View style={styles.toolbarRow}>
|
|
3415
4059
|
<View style={styles.searchContainer}>
|
|
3416
4060
|
<SearchIcon color={AppColors.grayTextWeak} size={16}/>
|
|
@@ -3561,17 +4205,17 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3561
4205
|
styles.listContent,
|
|
3562
4206
|
filteredLogs.length === 0 && { flexGrow: 1 },
|
|
3563
4207
|
]} keyboardShouldPersistTaps="handled"/>
|
|
3564
|
-
{
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
4208
|
+
{/* #2 — always-visible scroll-to-top, bottom right */}
|
|
4209
|
+
<TouchableScale onPress={() => {
|
|
4210
|
+
apisListRef.current?.scrollToOffset({
|
|
4211
|
+
offset: 0,
|
|
4212
|
+
animated: true,
|
|
4213
|
+
});
|
|
4214
|
+
}} hitSlop={10} style={styles.scrollTopBtn}>
|
|
4215
|
+
<View style={{ transform: [{ rotate: '180deg' }] }}>
|
|
4216
|
+
<ChevronIcon color="#FFFFFF" size={18}/>
|
|
4217
|
+
</View>
|
|
4218
|
+
</TouchableScale>
|
|
3575
4219
|
</View>) : activeTab === 'logs' ? (<View style={{ flex: 1 }}>
|
|
3576
4220
|
<View style={{
|
|
3577
4221
|
backgroundColor: '#FFFFFF',
|
|
@@ -3620,15 +4264,25 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3620
4264
|
backgroundColor: '#F4EBFF',
|
|
3621
4265
|
},
|
|
3622
4266
|
]}>
|
|
3623
|
-
|
|
4267
|
+
{/* #7 */}
|
|
4268
|
+
<View style={{
|
|
4269
|
+
flexDirection: 'row',
|
|
4270
|
+
alignItems: 'center',
|
|
4271
|
+
gap: 5,
|
|
4272
|
+
}}>
|
|
4273
|
+
<LayersIcon size={12} color={active
|
|
4274
|
+
? AppColors.purpleShade700
|
|
4275
|
+
: AppColors.grayTextStrong}/>
|
|
4276
|
+
<Text numberOfLines={1} style={[
|
|
3624
4277
|
styles.statusFilterText,
|
|
3625
4278
|
active && {
|
|
3626
4279
|
color: AppColors.purpleShade700,
|
|
3627
4280
|
fontFamily: AppFonts.interBold,
|
|
3628
4281
|
},
|
|
3629
4282
|
]}>
|
|
3630
|
-
|
|
3631
|
-
|
|
4283
|
+
All ({logCounts.all})
|
|
4284
|
+
</Text>
|
|
4285
|
+
</View>
|
|
3632
4286
|
</View>
|
|
3633
4287
|
</TouchableScale>);
|
|
3634
4288
|
})()}
|
|
@@ -3654,15 +4308,25 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3654
4308
|
backgroundColor: '#F1F5F9',
|
|
3655
4309
|
},
|
|
3656
4310
|
]}>
|
|
3657
|
-
|
|
4311
|
+
{/* #7 */}
|
|
4312
|
+
<View style={{
|
|
4313
|
+
flexDirection: 'row',
|
|
4314
|
+
alignItems: 'center',
|
|
4315
|
+
gap: 5,
|
|
4316
|
+
}}>
|
|
4317
|
+
<UserIcon size={12} color={active
|
|
4318
|
+
? '#334155'
|
|
4319
|
+
: AppColors.grayTextStrong}/>
|
|
4320
|
+
<Text numberOfLines={1} style={[
|
|
3658
4321
|
styles.statusFilterText,
|
|
3659
4322
|
active && {
|
|
3660
4323
|
color: '#334155',
|
|
3661
4324
|
fontFamily: AppFonts.interBold,
|
|
3662
4325
|
},
|
|
3663
4326
|
]}>
|
|
3664
|
-
|
|
3665
|
-
|
|
4327
|
+
User Log ({logCounts['user-log']})
|
|
4328
|
+
</Text>
|
|
4329
|
+
</View>
|
|
3666
4330
|
</View>
|
|
3667
4331
|
</TouchableScale>);
|
|
3668
4332
|
})()}
|
|
@@ -3688,15 +4352,25 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3688
4352
|
backgroundColor: AppColors.purpleShade50,
|
|
3689
4353
|
},
|
|
3690
4354
|
]}>
|
|
3691
|
-
|
|
4355
|
+
{/* #7 */}
|
|
4356
|
+
<View style={{
|
|
4357
|
+
flexDirection: 'row',
|
|
4358
|
+
alignItems: 'center',
|
|
4359
|
+
gap: 5,
|
|
4360
|
+
}}>
|
|
4361
|
+
<InfoCircleIcon size={12} color={active
|
|
4362
|
+
? AppColors.purple
|
|
4363
|
+
: AppColors.grayTextStrong}/>
|
|
4364
|
+
<Text numberOfLines={1} style={[
|
|
3692
4365
|
styles.statusFilterText,
|
|
3693
4366
|
active && {
|
|
3694
4367
|
color: AppColors.purple,
|
|
3695
4368
|
fontFamily: AppFonts.interBold,
|
|
3696
4369
|
},
|
|
3697
4370
|
]}>
|
|
3698
|
-
|
|
3699
|
-
|
|
4371
|
+
Info ({logCounts.info})
|
|
4372
|
+
</Text>
|
|
4373
|
+
</View>
|
|
3700
4374
|
</View>
|
|
3701
4375
|
</TouchableScale>);
|
|
3702
4376
|
})()}
|
|
@@ -3722,7 +4396,17 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3722
4396
|
backgroundColor: '#FFFDF6',
|
|
3723
4397
|
},
|
|
3724
4398
|
]}>
|
|
3725
|
-
|
|
4399
|
+
{/* #7 */}
|
|
4400
|
+
<View style={{
|
|
4401
|
+
flexDirection: 'row',
|
|
4402
|
+
alignItems: 'center',
|
|
4403
|
+
gap: 5,
|
|
4404
|
+
}}>
|
|
4405
|
+
<WarningTriangleIcon size={12} color={active
|
|
4406
|
+
? AppColors.darkOrange ||
|
|
4407
|
+
AppColors.lightOrange
|
|
4408
|
+
: AppColors.grayTextStrong}/>
|
|
4409
|
+
<Text numberOfLines={1} style={[
|
|
3726
4410
|
styles.statusFilterText,
|
|
3727
4411
|
active && {
|
|
3728
4412
|
color: AppColors.darkOrange ||
|
|
@@ -3730,8 +4414,9 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3730
4414
|
fontFamily: AppFonts.interBold,
|
|
3731
4415
|
},
|
|
3732
4416
|
]}>
|
|
3733
|
-
|
|
3734
|
-
|
|
4417
|
+
Warning ({logCounts.warn})
|
|
4418
|
+
</Text>
|
|
4419
|
+
</View>
|
|
3735
4420
|
</View>
|
|
3736
4421
|
</TouchableScale>);
|
|
3737
4422
|
})()}
|
|
@@ -3757,15 +4442,25 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3757
4442
|
backgroundColor: '#FFF5F6',
|
|
3758
4443
|
},
|
|
3759
4444
|
]}>
|
|
3760
|
-
|
|
4445
|
+
{/* #7 */}
|
|
4446
|
+
<View style={{
|
|
4447
|
+
flexDirection: 'row',
|
|
4448
|
+
alignItems: 'center',
|
|
4449
|
+
gap: 5,
|
|
4450
|
+
}}>
|
|
4451
|
+
<ErrorCircleIcon size={12} color={active
|
|
4452
|
+
? AppColors.errorColor
|
|
4453
|
+
: AppColors.grayTextStrong}/>
|
|
4454
|
+
<Text numberOfLines={1} style={[
|
|
3761
4455
|
styles.statusFilterText,
|
|
3762
4456
|
active && {
|
|
3763
4457
|
color: AppColors.errorColor,
|
|
3764
4458
|
fontFamily: AppFonts.interBold,
|
|
3765
4459
|
},
|
|
3766
4460
|
]}>
|
|
3767
|
-
|
|
3768
|
-
|
|
4461
|
+
Error ({logCounts.error})
|
|
4462
|
+
</Text>
|
|
4463
|
+
</View>
|
|
3769
4464
|
</View>
|
|
3770
4465
|
</TouchableScale>);
|
|
3771
4466
|
})()}
|
|
@@ -3791,15 +4486,25 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3791
4486
|
backgroundColor: `${AppColors.skyBlue}15`,
|
|
3792
4487
|
},
|
|
3793
4488
|
]}>
|
|
3794
|
-
|
|
4489
|
+
{/* #7 */}
|
|
4490
|
+
<View style={{
|
|
4491
|
+
flexDirection: 'row',
|
|
4492
|
+
alignItems: 'center',
|
|
4493
|
+
gap: 5,
|
|
4494
|
+
}}>
|
|
4495
|
+
<AnalyticsIcon size={12} color={active
|
|
4496
|
+
? AppColors.skyBlue
|
|
4497
|
+
: AppColors.grayTextStrong}/>
|
|
4498
|
+
<Text numberOfLines={1} style={[
|
|
3795
4499
|
styles.statusFilterText,
|
|
3796
4500
|
active && {
|
|
3797
4501
|
color: AppColors.skyBlue,
|
|
3798
4502
|
fontFamily: AppFonts.interBold,
|
|
3799
4503
|
},
|
|
3800
4504
|
]}>
|
|
3801
|
-
|
|
3802
|
-
|
|
4505
|
+
Analytics ({logCounts.analytics})
|
|
4506
|
+
</Text>
|
|
4507
|
+
</View>
|
|
3803
4508
|
</View>
|
|
3804
4509
|
</TouchableScale>);
|
|
3805
4510
|
})()}
|
|
@@ -4556,13 +5261,13 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
4556
5261
|
<View style={[
|
|
4557
5262
|
styles.methodBadge,
|
|
4558
5263
|
{
|
|
4559
|
-
backgroundColor:
|
|
5264
|
+
backgroundColor: METHOD_COLORS[selected.method] ?? METHOD_COLORS.ALL,
|
|
4560
5265
|
},
|
|
4561
5266
|
]}>
|
|
4562
5267
|
<Text style={[
|
|
4563
5268
|
styles.methodBadgeText,
|
|
4564
5269
|
{
|
|
4565
|
-
color:
|
|
5270
|
+
color: '#FFFFFF',
|
|
4566
5271
|
},
|
|
4567
5272
|
]}>
|
|
4568
5273
|
{selected.method}
|
|
@@ -4872,4 +5577,4 @@ export { setupConsoleLogger, clearConsoleLogs, subscribeConsoleLogs, } from './c
|
|
|
4872
5577
|
export { setupAnalyticsLogger, logAnalyticsEvent, subscribeAnalyticsEvents, clearAnalyticsEvents, } from './customHooks/analyticsLogger';
|
|
4873
5578
|
export { WebView, getWebViewLogs, getWebViewNavHistory, getWebViewHtml, getWebViewCss, getWebViewJs, getWebViewHtmlUrl, clearWebViewData, subscribeWebView, } from './customHooks/webViewLogger';
|
|
4874
5579
|
export { default as ErrorBoundary } from './components/ErrorBoundary';
|
|
4875
|
-
export { connectReduxStore, getReduxState, subscribeReduxState, } from './customHooks/reduxLogger';
|
|
5580
|
+
export { connectReduxStore, inspectorReduxMiddleware, getReduxState, subscribeReduxState, getActionHistory, clearActionHistory, } from './customHooks/reduxLogger';
|