react-native-inapp-inspector 1.1.3 → 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 +16 -0
- package/dist/commonjs/components/LogCard.js +2 -2
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/helpers/settingsStore.d.ts +5 -1
- package/dist/commonjs/helpers/settingsStore.js +56 -38
- package/dist/commonjs/index.js +348 -166
- package/dist/esm/components/LogCard.js +2 -2
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/helpers/settingsStore.d.ts +5 -1
- package/dist/esm/helpers/settingsStore.js +55 -38
- package/dist/esm/index.js +350 -168
- package/example/package-lock.json +74 -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';
|
|
@@ -24,7 +24,7 @@ import AnimatedEntrance from './components/AnimatedEntrance';
|
|
|
24
24
|
// Helpers
|
|
25
25
|
import { formatDateTime, getStatusColor, getNavigationInfo, deduplicateLogs, getDomainColor, formatDisplayUrl, getFetchCommand, getCurlCommand, getSize, } from './helpers';
|
|
26
26
|
// #5 — settings persistence
|
|
27
|
-
import { loadSettings, saveSettings } from './helpers/settingsStore';
|
|
27
|
+
import { loadSettings, saveSettings, setCustomStorage, isPersistentStorageAvailable, clearPersistedSettings, } from './helpers/settingsStore';
|
|
28
28
|
// Assets
|
|
29
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';
|
|
30
30
|
import ErrorBoundary from './components/ErrorBoundary';
|
|
@@ -113,7 +113,9 @@ const NavigationTracker = ({ onStateChange }) => {
|
|
|
113
113
|
const animateNextLayout = () => {
|
|
114
114
|
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
115
115
|
};
|
|
116
|
-
const NetworkInspector = ({ enabled = true, }) => {
|
|
116
|
+
const NetworkInspector = ({ enabled = true, storage, }) => {
|
|
117
|
+
// Set custom storage synchronously during render phase
|
|
118
|
+
setCustomStorage(storage || null);
|
|
117
119
|
const [isDark, setIsDark] = useState(false);
|
|
118
120
|
const [reduxState, setReduxState] = useState(null);
|
|
119
121
|
// Action timeline + per-reducer last action are kept in component state so the
|
|
@@ -195,11 +197,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
195
197
|
const visibleConsoleLogs = useMemo(() => {
|
|
196
198
|
const filtered = consoleLogs.filter(log => {
|
|
197
199
|
const type = log.type;
|
|
198
|
-
if (type === 'info' && !showConsoleLevels
|
|
200
|
+
if (type === 'info' && !showConsoleLevels?.info)
|
|
199
201
|
return false;
|
|
200
|
-
if (type === 'warn' && !showConsoleLevels
|
|
202
|
+
if (type === 'warn' && !showConsoleLevels?.warn)
|
|
201
203
|
return false;
|
|
202
|
-
if (type === 'error' && !showConsoleLevels
|
|
204
|
+
if (type === 'error' && !showConsoleLevels?.error)
|
|
203
205
|
return false;
|
|
204
206
|
const message = log.message || '';
|
|
205
207
|
const allPrefixes = [
|
|
@@ -229,9 +231,9 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
229
231
|
insights: true,
|
|
230
232
|
apis: true,
|
|
231
233
|
logs: true,
|
|
232
|
-
analytics:
|
|
233
|
-
webview:
|
|
234
|
-
redux:
|
|
234
|
+
analytics: false,
|
|
235
|
+
webview: false,
|
|
236
|
+
redux: false,
|
|
235
237
|
});
|
|
236
238
|
const [maxNetworkLogs, setMaxNetworkLogs] = useState(100);
|
|
237
239
|
const [webViewCaptureCssJs, setWebViewCaptureCssJs] = useState(true);
|
|
@@ -241,9 +243,36 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
241
243
|
const [insightsShowConsoleAlerts, setInsightsShowConsoleAlerts] = useState(true);
|
|
242
244
|
// #6 — tab the inspector opens on. Shown with a DEFAULT badge in Settings.
|
|
243
245
|
const [defaultTab, setDefaultTab] = useState('apis');
|
|
244
|
-
// #9 — when false (default), consecutive identical entries in the API and
|
|
245
|
-
// Console lists are collapsed into one row with a ×N counter.
|
|
246
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
|
+
};
|
|
247
276
|
// #5 — hydrate persisted settings once, then auto-save on any change.
|
|
248
277
|
const settingsHydratedRef = useRef(false);
|
|
249
278
|
useEffect(() => {
|
|
@@ -290,9 +319,9 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
290
319
|
insights: true,
|
|
291
320
|
apis: true,
|
|
292
321
|
logs: true,
|
|
293
|
-
analytics:
|
|
294
|
-
webview:
|
|
295
|
-
redux:
|
|
322
|
+
analytics: false,
|
|
323
|
+
webview: false,
|
|
324
|
+
redux: false,
|
|
296
325
|
},
|
|
297
326
|
...(saved.tabVisibility || {}),
|
|
298
327
|
apis: true,
|
|
@@ -619,7 +648,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
619
648
|
// #6 — every time the inspector is opened, land on the chosen default tab.
|
|
620
649
|
useEffect(() => {
|
|
621
650
|
if (visible) {
|
|
622
|
-
const target = defaultTab === 'apis' || tabVisibility[defaultTab]
|
|
651
|
+
const target = defaultTab === 'apis' || tabVisibility?.[defaultTab]
|
|
623
652
|
? defaultTab
|
|
624
653
|
: 'apis';
|
|
625
654
|
setActiveTab(target);
|
|
@@ -1289,7 +1318,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1289
1318
|
return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
|
|
1290
1319
|
{/* Settings Header with back button */}
|
|
1291
1320
|
<LinearGradient colors={[AppColors.purple, '#6B4EFF']} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.headerGradient}>
|
|
1292
|
-
<
|
|
1321
|
+
<SafeAreaView style={{ width: '100%' }}>
|
|
1322
|
+
<View style={[styles.header, { paddingHorizontal: 16, gap: 12 }]}>
|
|
1293
1323
|
<TouchableScale onPress={() => {
|
|
1294
1324
|
animateNextLayout();
|
|
1295
1325
|
setSettingsPage(null);
|
|
@@ -1337,7 +1367,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1337
1367
|
</Text>
|
|
1338
1368
|
</View>
|
|
1339
1369
|
</View>
|
|
1340
|
-
</
|
|
1370
|
+
</SafeAreaView>
|
|
1371
|
+
</LinearGradient>
|
|
1341
1372
|
|
|
1342
1373
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
|
|
1343
1374
|
{/* Tab list */}
|
|
@@ -1382,7 +1413,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1382
1413
|
</View>
|
|
1383
1414
|
|
|
1384
1415
|
{settingsTabs.map((tab, idx) => {
|
|
1385
|
-
const isVisible = tab.key === 'apis' || tabVisibility[tab.key];
|
|
1416
|
+
const isVisible = tab.key === 'apis' || tabVisibility?.[tab.key];
|
|
1386
1417
|
const isLast = idx === settingsTabs.length - 1;
|
|
1387
1418
|
const isLocked = tab.key === 'apis';
|
|
1388
1419
|
return (<View key={tab.key} style={{
|
|
@@ -1762,40 +1793,63 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1762
1793
|
</View>
|
|
1763
1794
|
</View>
|
|
1764
1795
|
|
|
1765
|
-
{/*
|
|
1796
|
+
{/* Grid of Default Tab Cards */}
|
|
1766
1797
|
<View style={{
|
|
1767
1798
|
flexDirection: 'row',
|
|
1768
1799
|
flexWrap: 'wrap',
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
padding: 2.5,
|
|
1772
|
-
marginTop: 10,
|
|
1773
|
-
borderWidth: 1,
|
|
1774
|
-
borderColor: AppColors.dividerColor,
|
|
1775
|
-
gap: 2,
|
|
1800
|
+
gap: 8,
|
|
1801
|
+
marginTop: 12,
|
|
1776
1802
|
}}>
|
|
1777
1803
|
{settingsTabs
|
|
1778
|
-
.filter(tab => tab.key === 'apis' || tabVisibility[tab.key])
|
|
1804
|
+
.filter(tab => tab.key === 'apis' || tabVisibility?.[tab.key])
|
|
1779
1805
|
.map(tab => {
|
|
1780
1806
|
const isActive = defaultTab === tab.key;
|
|
1781
1807
|
return (<TouchableScale key={tab.key} onPress={() => setDefaultTab(tab.key)} style={{
|
|
1782
|
-
|
|
1783
|
-
paddingHorizontal: 10,
|
|
1808
|
+
flexDirection: 'row',
|
|
1784
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,
|
|
1785
1823
|
borderRadius: 6,
|
|
1786
|
-
backgroundColor: isActive
|
|
1787
|
-
|
|
1788
|
-
|
|
1824
|
+
backgroundColor: isActive ? AppColors.purple : AppColors.purpleShade50,
|
|
1825
|
+
alignItems: 'center',
|
|
1826
|
+
justifyContent: 'center',
|
|
1789
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>
|
|
1790
1835
|
<Text style={{
|
|
1791
1836
|
fontFamily: AppFonts.interBold,
|
|
1792
|
-
fontSize:
|
|
1793
|
-
color: isActive
|
|
1794
|
-
|
|
1795
|
-
: AppColors.grayText,
|
|
1837
|
+
fontSize: 13,
|
|
1838
|
+
color: isActive ? AppColors.purple : AppColors.primaryBlack,
|
|
1839
|
+
flex: 1,
|
|
1796
1840
|
}}>
|
|
1797
|
-
|
|
1841
|
+
{tab.label}
|
|
1798
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>)}
|
|
1799
1853
|
</TouchableScale>);
|
|
1800
1854
|
})}
|
|
1801
1855
|
</View>
|
|
@@ -1877,73 +1931,130 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
1877
1931
|
}}/>
|
|
1878
1932
|
</TouchableScale>
|
|
1879
1933
|
</View>
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
justifyContent: 'center',
|
|
1907
|
-
}}>
|
|
1908
|
-
<WhiteBackNavigation color={AppColors.purple} size={16}/>
|
|
1909
|
-
</TouchableScale>
|
|
1910
|
-
{icon && (<View style={{
|
|
1911
|
-
width: 36,
|
|
1912
|
-
height: 36,
|
|
1913
|
-
borderRadius: 10,
|
|
1914
|
-
backgroundColor: AppColors.purpleShade50,
|
|
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)',
|
|
1915
1960
|
borderWidth: 1,
|
|
1916
|
-
borderColor: 'rgba(
|
|
1961
|
+
borderColor: 'rgba(239,68,68,0.2)',
|
|
1917
1962
|
alignItems: 'center',
|
|
1918
1963
|
justifyContent: 'center',
|
|
1919
1964
|
}}>
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
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={{
|
|
1932
1987
|
paddingHorizontal: 10,
|
|
1933
1988
|
paddingVertical: 5,
|
|
1934
|
-
borderRadius:
|
|
1989
|
+
borderRadius: 7,
|
|
1990
|
+
backgroundColor: 'rgba(255,46,87,0.08)',
|
|
1935
1991
|
borderWidth: 1,
|
|
1936
|
-
borderColor: 'rgba(
|
|
1992
|
+
borderColor: 'rgba(255,46,87,0.2)',
|
|
1937
1993
|
}}>
|
|
1938
|
-
|
|
1994
|
+
<Text style={{
|
|
1939
1995
|
fontFamily: AppFonts.interBold,
|
|
1940
1996
|
fontSize: 11,
|
|
1941
|
-
color: AppColors.
|
|
1997
|
+
color: AppColors.errorColor,
|
|
1942
1998
|
}}>
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
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
|
+
};
|
|
1947
2058
|
// Helper: settings row with icon + label + optional description
|
|
1948
2059
|
const renderSettingRow = (opts) => (<View style={{
|
|
1949
2060
|
paddingVertical: 12,
|
|
@@ -2023,9 +2134,15 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2023
2134
|
})}
|
|
2024
2135
|
</View>)}
|
|
2025
2136
|
</View>);
|
|
2137
|
+
let content = null;
|
|
2138
|
+
let title = '';
|
|
2139
|
+
let icon = null;
|
|
2140
|
+
let rightInfo = '';
|
|
2026
2141
|
if (settingsPage === 'apis') {
|
|
2027
|
-
|
|
2028
|
-
|
|
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 }}>
|
|
2029
2146
|
<View style={{
|
|
2030
2147
|
backgroundColor: AppColors.primaryLight,
|
|
2031
2148
|
padding: 16,
|
|
@@ -2085,9 +2202,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2085
2202
|
</View>
|
|
2086
2203
|
</ScrollView>);
|
|
2087
2204
|
}
|
|
2088
|
-
if (settingsPage === 'logs') {
|
|
2089
|
-
|
|
2090
|
-
|
|
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 }}>
|
|
2091
2210
|
<View style={{
|
|
2092
2211
|
backgroundColor: AppColors.primaryLight,
|
|
2093
2212
|
padding: 16,
|
|
@@ -2116,7 +2235,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2116
2235
|
Log Levels
|
|
2117
2236
|
</Text>
|
|
2118
2237
|
{['info', 'warn', 'error'].map((level, li) => {
|
|
2119
|
-
const isLvlActive = showConsoleLevels[level];
|
|
2238
|
+
const isLvlActive = showConsoleLevels?.[level];
|
|
2120
2239
|
const levelColor = level === 'error'
|
|
2121
2240
|
? AppColors.errorColor
|
|
2122
2241
|
: level === 'warn'
|
|
@@ -2197,9 +2316,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2197
2316
|
</View>
|
|
2198
2317
|
</ScrollView>);
|
|
2199
2318
|
}
|
|
2200
|
-
if (settingsPage === 'analytics') {
|
|
2201
|
-
|
|
2202
|
-
|
|
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 }}>
|
|
2203
2324
|
<View style={{
|
|
2204
2325
|
backgroundColor: AppColors.primaryLight,
|
|
2205
2326
|
padding: 16,
|
|
@@ -2253,9 +2374,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2253
2374
|
</View>
|
|
2254
2375
|
</ScrollView>);
|
|
2255
2376
|
}
|
|
2256
|
-
if (settingsPage === 'webview') {
|
|
2257
|
-
|
|
2258
|
-
|
|
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 }}>
|
|
2259
2382
|
<View style={{
|
|
2260
2383
|
backgroundColor: AppColors.primaryLight,
|
|
2261
2384
|
padding: 16,
|
|
@@ -2325,9 +2448,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2325
2448
|
</View>
|
|
2326
2449
|
</ScrollView>);
|
|
2327
2450
|
}
|
|
2328
|
-
if (settingsPage === 'redux') {
|
|
2329
|
-
|
|
2330
|
-
|
|
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 }}>
|
|
2331
2456
|
<View style={{
|
|
2332
2457
|
backgroundColor: AppColors.primaryLight,
|
|
2333
2458
|
padding: 16,
|
|
@@ -2411,53 +2536,108 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2411
2536
|
</View>
|
|
2412
2537
|
</ScrollView>);
|
|
2413
2538
|
}
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
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)',
|
|
2421
2596
|
borderWidth: 1,
|
|
2422
|
-
borderColor:
|
|
2423
|
-
gap: 4,
|
|
2597
|
+
borderColor: 'rgba(255, 255, 255, 0.08)',
|
|
2424
2598
|
}}>
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
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>);
|
|
2461
2641
|
};
|
|
2462
2642
|
const renderInsightsDashboard = () => {
|
|
2463
2643
|
const apiTotal = logs.length;
|
|
@@ -2493,11 +2673,11 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2493
2673
|
const totalSignals = apiTotal + logTotal + analyticsTotal + webviewTotal;
|
|
2494
2674
|
const totalIssues = apiErrors + logErrors;
|
|
2495
2675
|
const activeModules = [
|
|
2496
|
-
tabVisibility
|
|
2497
|
-
tabVisibility
|
|
2498
|
-
tabVisibility
|
|
2499
|
-
tabVisibility
|
|
2500
|
-
tabVisibility
|
|
2676
|
+
tabVisibility?.apis,
|
|
2677
|
+
tabVisibility?.logs,
|
|
2678
|
+
tabVisibility?.analytics,
|
|
2679
|
+
tabVisibility?.webview,
|
|
2680
|
+
tabVisibility?.redux,
|
|
2501
2681
|
].filter(Boolean).length;
|
|
2502
2682
|
// Composite health score: success rate penalised by error volume and slow requests.
|
|
2503
2683
|
const healthScore = totalSignals === 0
|
|
@@ -2664,7 +2844,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2664
2844
|
</View>
|
|
2665
2845
|
|
|
2666
2846
|
{/* Module 1: APIs */}
|
|
2667
|
-
{tabVisibility
|
|
2847
|
+
{tabVisibility?.apis && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('apis')}>
|
|
2668
2848
|
<View style={styles.dashboardModuleHeader}>
|
|
2669
2849
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2670
2850
|
<SignalIcon color={AppColors.purple} size={18}/>
|
|
@@ -2771,7 +2951,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2771
2951
|
</View>)}
|
|
2772
2952
|
</View>
|
|
2773
2953
|
</TouchableScale>)}
|
|
2774
|
-
{tabVisibility
|
|
2954
|
+
{tabVisibility?.logs && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('logs')}>
|
|
2775
2955
|
<View style={styles.dashboardModuleHeader}>
|
|
2776
2956
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2777
2957
|
<TerminalIcon color="#0D9488" size={18}/>
|
|
@@ -2812,7 +2992,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2812
2992
|
</TouchableScale>)}
|
|
2813
2993
|
|
|
2814
2994
|
{/* Module 3: Analytics */}
|
|
2815
|
-
{tabVisibility
|
|
2995
|
+
{tabVisibility?.analytics && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('analytics')}>
|
|
2816
2996
|
<View style={styles.dashboardModuleHeader}>
|
|
2817
2997
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2818
2998
|
<AnalyticsIcon color="#EA580C" size={18}/>
|
|
@@ -2849,7 +3029,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2849
3029
|
</TouchableScale>)}
|
|
2850
3030
|
|
|
2851
3031
|
{/* Module 4: WebView */}
|
|
2852
|
-
{tabVisibility
|
|
3032
|
+
{tabVisibility?.webview && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('webview')}>
|
|
2853
3033
|
<View style={styles.dashboardModuleHeader}>
|
|
2854
3034
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2855
3035
|
<GlobeIcon color="#2563EB" size={18}/>
|
|
@@ -2882,7 +3062,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
2882
3062
|
</TouchableScale>)}
|
|
2883
3063
|
|
|
2884
3064
|
{/* Module 5: Redux Store */}
|
|
2885
|
-
{tabVisibility
|
|
3065
|
+
{tabVisibility?.redux && (<TouchableScale style={styles.dashboardModuleCard} onPress={() => switchActiveTab('redux')}>
|
|
2886
3066
|
<View style={styles.dashboardModuleHeader}>
|
|
2887
3067
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
2888
3068
|
<TerminalIcon color={AppColors.purple} size={18}/>
|
|
@@ -3195,7 +3375,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3195
3375
|
<StatusBar translucent backgroundColor="transparent" barStyle="light-content"/>
|
|
3196
3376
|
|
|
3197
3377
|
<LinearGradient colors={[AppColors.purple, '#6B4EFF']} style={styles.headerGradient}>
|
|
3198
|
-
<
|
|
3378
|
+
<SafeAreaView style={{ width: '100%' }}>
|
|
3379
|
+
<View style={styles.header}>
|
|
3199
3380
|
<View style={[
|
|
3200
3381
|
styles.headerLeft,
|
|
3201
3382
|
{
|
|
@@ -3532,7 +3713,8 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3532
3713
|
</TouchableScale>
|
|
3533
3714
|
</View>
|
|
3534
3715
|
</View>
|
|
3535
|
-
</
|
|
3716
|
+
</SafeAreaView>
|
|
3717
|
+
</LinearGradient>
|
|
3536
3718
|
|
|
3537
3719
|
{/* ─── Horizontal Scrollable Tab Bar inside Content ─── */}
|
|
3538
3720
|
{selected == null &&
|
|
@@ -3577,7 +3759,7 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
3577
3759
|
icon: 'redux',
|
|
3578
3760
|
},
|
|
3579
3761
|
]
|
|
3580
|
-
.filter(tab => tabVisibility[tab.key])
|
|
3762
|
+
.filter(tab => tabVisibility?.[tab.key])
|
|
3581
3763
|
.map(tab => {
|
|
3582
3764
|
const isActive = activeTab === tab.key;
|
|
3583
3765
|
const iconColor = isActive
|
|
@@ -5079,13 +5261,13 @@ const NetworkInspector = ({ enabled = true, }) => {
|
|
|
5079
5261
|
<View style={[
|
|
5080
5262
|
styles.methodBadge,
|
|
5081
5263
|
{
|
|
5082
|
-
backgroundColor:
|
|
5264
|
+
backgroundColor: METHOD_COLORS[selected.method] ?? METHOD_COLORS.ALL,
|
|
5083
5265
|
},
|
|
5084
5266
|
]}>
|
|
5085
5267
|
<Text style={[
|
|
5086
5268
|
styles.methodBadgeText,
|
|
5087
5269
|
{
|
|
5088
|
-
color:
|
|
5270
|
+
color: '#FFFFFF',
|
|
5089
5271
|
},
|
|
5090
5272
|
]}>
|
|
5091
5273
|
{selected.method}
|