react-native-inapp-inspector 2.3.7 → 2.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +27 -2
- package/dist/commonjs/components/Inspector/BundleTab.js +3 -0
- package/dist/commonjs/components/Inspector/ConsoleTab.js +24 -1
- package/dist/commonjs/components/Inspector/CrashTab.js +30 -1
- package/dist/commonjs/components/Inspector/FeatureUnderDevNotice.d.ts +7 -0
- package/dist/commonjs/components/Inspector/FeatureUnderDevNotice.js +111 -0
- package/dist/commonjs/components/Inspector/InspectorHeader.js +225 -108
- package/dist/commonjs/components/Inspector/NpmUpdateToast.js +1 -1
- package/dist/commonjs/components/Inspector/PerformanceTab.js +3 -0
- package/dist/commonjs/components/Inspector/ReduxTab.js +24 -1
- package/dist/commonjs/components/Inspector/SettingsPanel.js +73 -88
- package/dist/commonjs/components/Inspector/StorageTab.js +37 -11
- package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +2 -0
- package/dist/commonjs/components/LogCard.js +33 -3
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/networkLogger.js +2 -0
- package/dist/commonjs/helpers/telemetry.js +34 -0
- package/dist/commonjs/index.js +3 -0
- package/dist/esm/components/Inspector/AnalyticsTab.js +29 -4
- package/dist/esm/components/Inspector/BundleTab.js +3 -0
- package/dist/esm/components/Inspector/ConsoleTab.js +26 -3
- package/dist/esm/components/Inspector/CrashTab.js +32 -3
- package/dist/esm/components/Inspector/FeatureUnderDevNotice.d.ts +7 -0
- package/dist/esm/components/Inspector/FeatureUnderDevNotice.js +74 -0
- package/dist/esm/components/Inspector/InspectorHeader.js +226 -109
- package/dist/esm/components/Inspector/NpmUpdateToast.js +1 -1
- package/dist/esm/components/Inspector/PerformanceTab.js +3 -0
- package/dist/esm/components/Inspector/ReduxTab.js +26 -3
- package/dist/esm/components/Inspector/SettingsPanel.js +73 -88
- package/dist/esm/components/Inspector/StorageTab.js +39 -13
- package/dist/esm/components/Inspector/UpdateAvailableModal.js +2 -0
- package/dist/esm/components/LogCard.js +34 -4
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/networkLogger.js +2 -0
- package/dist/esm/helpers/telemetry.js +34 -0
- package/dist/esm/index.js +3 -0
- package/package.json +1 -1
- package/src/components/Inspector/AnalyticsTab.tsx +71 -43
- package/src/components/Inspector/BundleTab.tsx +3 -0
- package/src/components/Inspector/ConsoleTab.tsx +28 -1
- package/src/components/Inspector/CrashTab.tsx +45 -14
- package/src/components/Inspector/FeatureUnderDevNotice.tsx +94 -0
- package/src/components/Inspector/InspectorHeader.tsx +257 -115
- package/src/components/Inspector/NpmUpdateToast.tsx +1 -1
- package/src/components/Inspector/PerformanceTab.tsx +3 -0
- package/src/components/Inspector/ReduxTab.tsx +28 -1
- package/src/components/Inspector/SettingsPanel.tsx +93 -132
- package/src/components/Inspector/StorageTab.tsx +56 -27
- package/src/components/Inspector/UpdateAvailableModal.tsx +2 -0
- package/src/components/LogCard.tsx +41 -4
- package/src/constants/version.ts +1 -1
- package/src/customHooks/networkLogger.ts +2 -0
- package/src/helpers/telemetry.ts +36 -0
- package/src/index.tsx +5 -0
|
@@ -92,7 +92,7 @@ export const NpmUpdateToast = () => {
|
|
|
92
92
|
Linking.openURL('https://www.npmjs.com/package/react-native-inapp-inspector').catch(() => { });
|
|
93
93
|
handleDismiss();
|
|
94
94
|
};
|
|
95
|
-
if (!showUpdateToast || !visible || !updateAvailable || !latestNpmVersion)
|
|
95
|
+
if (typeof __DEV__ === 'undefined' || !__DEV__ || !showUpdateToast || !visible || !updateAvailable || !latestNpmVersion)
|
|
96
96
|
return null;
|
|
97
97
|
const progressWidth = progressAnim.interpolate({
|
|
98
98
|
inputRange: [0, 1],
|
|
@@ -5,6 +5,7 @@ import TouchableScale from '../TouchableScale';
|
|
|
5
5
|
import CopyButton from '../CopyButton';
|
|
6
6
|
import HighlightText from '../HighlightText';
|
|
7
7
|
import EndOfListFooter from '../EndOfListFooter';
|
|
8
|
+
import FeatureUnderDevNotice from './FeatureUnderDevNotice';
|
|
8
9
|
import { AppColors } from '../../styles/AppColors';
|
|
9
10
|
import { AppFonts } from '../../styles/AppFonts';
|
|
10
11
|
import { useTranslation } from '../../i18n';
|
|
@@ -356,6 +357,8 @@ const PerformanceTab = React.memo(() => {
|
|
|
356
357
|
</TouchableScale>
|
|
357
358
|
</View>
|
|
358
359
|
|
|
360
|
+
<FeatureUnderDevNotice featureName="Performance & FPS Profiler"/>
|
|
361
|
+
|
|
359
362
|
|
|
360
363
|
<View style={perfStyles.categoryScrollWrapper}>
|
|
361
364
|
<ScrollView horizontal showsHorizontalScrollIndicator={false} style={perfStyles.categoryScrollView} contentContainerStyle={perfStyles.categoryScroll}>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useMemo, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { FlatList, Pressable, StyleSheet, Text, TextInput, TouchableOpacity, View, } from 'react-native';
|
|
3
3
|
import { useTranslation } from '../../i18n';
|
|
4
4
|
import { useInspector } from './InspectorContext';
|
|
@@ -12,7 +12,7 @@ import styles from '../../styles';
|
|
|
12
12
|
import { AppColors } from '../../styles/AppColors';
|
|
13
13
|
import { AppFonts } from '../../styles/AppFonts';
|
|
14
14
|
import { getActionHistory, getReduxAutoRefresh, setReduxAutoRefresh, } from '../../customHooks/reduxLogger';
|
|
15
|
-
import { TerminalIcon, SearchIcon, ClearIcon, LayersIcon, ClockIcon, ForwardChevronIcon, SortArrowIcon, BoltIcon, AtomIcon, ScreenIcon, ListenerIcon, DocIcon, LoadingSpinnerIcon, CircleAlertIcon, TextAaIcon, HeaderPauseIcon, } from '../NetworkIcons';
|
|
15
|
+
import { TerminalIcon, SearchIcon, ClearIcon, LayersIcon, ClockIcon, ForwardChevronIcon, SortArrowIcon, BoltIcon, AtomIcon, ScreenIcon, ListenerIcon, DocIcon, LoadingSpinnerIcon, CircleAlertIcon, TextAaIcon, HeaderPauseIcon, ChevronIcon, } from '../NetworkIcons';
|
|
16
16
|
const getOriginBadge = (originType) => {
|
|
17
17
|
switch (originType) {
|
|
18
18
|
case 'saga':
|
|
@@ -60,6 +60,7 @@ const getOriginBadge = (originType) => {
|
|
|
60
60
|
const ReduxTab = React.memo(() => {
|
|
61
61
|
const { t } = useTranslation();
|
|
62
62
|
const { reduxState, reduxLastActionMap, reduxSearch, setReduxSearch, setSelectedReduxSlice, } = useInspector();
|
|
63
|
+
const listRef = useRef(null);
|
|
63
64
|
const [sortMode, setSortMode] = useState('latest');
|
|
64
65
|
const [isReduxPaused, setIsReduxPaused] = useState(!getReduxAutoRefresh());
|
|
65
66
|
const handleTogglePause = useCallback(() => {
|
|
@@ -453,10 +454,32 @@ const ReduxTab = React.memo(() => {
|
|
|
453
454
|
</View>
|
|
454
455
|
|
|
455
456
|
|
|
456
|
-
<FlatList data={filteredSlices} keyExtractor={item => item.id} renderItem={renderSliceItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={reduxSearch.length > 0}/>} ListFooterComponent={filteredSlices.length > 0 ? (<EndOfListFooter count={filteredSlices.length} label="slices"/>) : null} contentContainerStyle={[
|
|
457
|
+
<FlatList ref={listRef} data={filteredSlices} keyExtractor={item => item.id} renderItem={renderSliceItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={reduxSearch.length > 0}/>} ListFooterComponent={filteredSlices.length > 0 ? (<EndOfListFooter count={filteredSlices.length} label="slices"/>) : null} contentContainerStyle={[
|
|
457
458
|
reduxTabStyles.listContent,
|
|
458
459
|
filteredSlices.length === 0 && { flexGrow: 1 },
|
|
459
460
|
]} keyboardShouldPersistTaps="handled"/>
|
|
461
|
+
|
|
462
|
+
<TouchableScale onPress={() => {
|
|
463
|
+
try {
|
|
464
|
+
listRef.current?.scrollToOffset({
|
|
465
|
+
offset: 0,
|
|
466
|
+
animated: true,
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
catch {
|
|
470
|
+
try {
|
|
471
|
+
listRef.current?.scrollToIndex({
|
|
472
|
+
index: 0,
|
|
473
|
+
animated: true,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
catch { }
|
|
477
|
+
}
|
|
478
|
+
}} hitSlop={12} style={styles.scrollTopBtn}>
|
|
479
|
+
<View style={{ transform: [{ rotate: '180deg' }] }}>
|
|
480
|
+
<ChevronIcon color={AppColors.white} size={18}/>
|
|
481
|
+
</View>
|
|
482
|
+
</TouchableScale>
|
|
460
483
|
</View>);
|
|
461
484
|
});
|
|
462
485
|
const reduxTabStyles = StyleSheet.create({
|
|
@@ -275,11 +275,12 @@ const SettingsPanel = () => {
|
|
|
275
275
|
}}>
|
|
276
276
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, paddingBottom: 100, gap: 14 }} showsVerticalScrollIndicator={false}>
|
|
277
277
|
|
|
278
|
+
|
|
278
279
|
<View style={{
|
|
279
|
-
flexDirection: 'row',
|
|
280
280
|
backgroundColor: AppColors.primaryLight,
|
|
281
|
-
borderRadius:
|
|
282
|
-
|
|
281
|
+
borderRadius: 13,
|
|
282
|
+
paddingVertical: 4,
|
|
283
|
+
paddingHorizontal: 4,
|
|
283
284
|
borderWidth: 1,
|
|
284
285
|
borderColor: AppColors.grayBorderSecondary,
|
|
285
286
|
shadowColor: AppColors.black,
|
|
@@ -287,95 +288,79 @@ const SettingsPanel = () => {
|
|
|
287
288
|
shadowRadius: 4,
|
|
288
289
|
shadowOffset: { width: 0, height: 2 },
|
|
289
290
|
}}>
|
|
290
|
-
<
|
|
291
|
-
animateNextLayout();
|
|
292
|
-
setSettingsActiveSubTab('module');
|
|
293
|
-
}} style={{
|
|
294
|
-
flex: 1,
|
|
295
|
-
paddingVertical: 9,
|
|
291
|
+
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{
|
|
296
292
|
flexDirection: 'row',
|
|
297
293
|
alignItems: 'center',
|
|
298
|
-
justifyContent: 'center',
|
|
299
294
|
gap: 6,
|
|
300
|
-
|
|
301
|
-
backgroundColor: settingsActiveSubTab === 'module'
|
|
302
|
-
? AppColors.purple
|
|
303
|
-
: 'transparent',
|
|
304
|
-
}}>
|
|
305
|
-
<LayersIcon color={settingsActiveSubTab === 'module'
|
|
306
|
-
? AppColors.white
|
|
307
|
-
: AppColors.grayText} size={13}/>
|
|
308
|
-
<Text style={{
|
|
309
|
-
fontFamily: AppFonts.interBold,
|
|
310
|
-
fontSize: 12.5,
|
|
311
|
-
lineHeight: 16,
|
|
312
|
-
color: settingsActiveSubTab === 'module'
|
|
313
|
-
? AppColors.white
|
|
314
|
-
: AppColors.grayText,
|
|
315
|
-
}}>
|
|
316
|
-
{t('settings.modulesAndTools')}
|
|
317
|
-
</Text>
|
|
318
|
-
</TouchableScale>
|
|
319
|
-
|
|
320
|
-
<TouchableScale accessible={true} accessibilityRole="tab" accessibilityLabel={t('settings.uiPreferences')} accessibilityState={{ selected: settingsActiveSubTab === 'ui' }} onPress={() => {
|
|
321
|
-
animateNextLayout();
|
|
322
|
-
setSettingsActiveSubTab('ui');
|
|
323
|
-
}} style={{
|
|
324
|
-
flex: 1,
|
|
325
|
-
paddingVertical: 9,
|
|
326
|
-
flexDirection: 'row',
|
|
327
|
-
alignItems: 'center',
|
|
328
|
-
justifyContent: 'center',
|
|
329
|
-
gap: 5,
|
|
330
|
-
borderRadius: 9,
|
|
331
|
-
backgroundColor: settingsActiveSubTab === 'ui'
|
|
332
|
-
? AppColors.purple
|
|
333
|
-
: 'transparent',
|
|
334
|
-
}}>
|
|
335
|
-
<ScreenIcon color={settingsActiveSubTab === 'ui'
|
|
336
|
-
? AppColors.white
|
|
337
|
-
: AppColors.grayText} size={13}/>
|
|
338
|
-
<Text numberOfLines={1} style={{
|
|
339
|
-
fontFamily: AppFonts.interBold,
|
|
340
|
-
fontSize: 12,
|
|
341
|
-
lineHeight: 16,
|
|
342
|
-
color: settingsActiveSubTab === 'ui'
|
|
343
|
-
? AppColors.white
|
|
344
|
-
: AppColors.grayText,
|
|
345
|
-
}}>
|
|
346
|
-
{t('settings.uiPreferences')}
|
|
347
|
-
</Text>
|
|
348
|
-
</TouchableScale>
|
|
349
|
-
|
|
350
|
-
<TouchableScale accessible={true} accessibilityRole="tab" accessibilityLabel={t('settings.ramLimits')} accessibilityState={{ selected: settingsActiveSubTab === 'limits' }} onPress={() => {
|
|
351
|
-
animateNextLayout();
|
|
352
|
-
setSettingsActiveSubTab('limits');
|
|
353
|
-
}} style={{
|
|
354
|
-
flex: 1,
|
|
355
|
-
paddingVertical: 9,
|
|
356
|
-
flexDirection: 'row',
|
|
357
|
-
alignItems: 'center',
|
|
358
|
-
justifyContent: 'center',
|
|
359
|
-
gap: 5,
|
|
360
|
-
borderRadius: 9,
|
|
361
|
-
backgroundColor: settingsActiveSubTab === 'limits'
|
|
362
|
-
? AppColors.purple
|
|
363
|
-
: 'transparent',
|
|
364
|
-
}}>
|
|
365
|
-
<BrainIcon color={settingsActiveSubTab === 'limits'
|
|
366
|
-
? AppColors.white
|
|
367
|
-
: AppColors.grayText} size={13}/>
|
|
368
|
-
<Text numberOfLines={1} style={{
|
|
369
|
-
fontFamily: AppFonts.interBold,
|
|
370
|
-
fontSize: 12,
|
|
371
|
-
lineHeight: 16,
|
|
372
|
-
color: settingsActiveSubTab === 'limits'
|
|
373
|
-
? AppColors.white
|
|
374
|
-
: AppColors.grayText,
|
|
295
|
+
paddingHorizontal: 2,
|
|
375
296
|
}}>
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
297
|
+
{[
|
|
298
|
+
{
|
|
299
|
+
key: 'module',
|
|
300
|
+
label: t('settings.modulesAndTools', 'Modules & Tools'),
|
|
301
|
+
Icon: LayersIcon,
|
|
302
|
+
badge: `${allModules.filter(m => stagedTabVisibility?.[m.key] || m.key === 'apis').length}/${allModules.length}`,
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
key: 'ui',
|
|
306
|
+
label: t('settings.uiPreferences', 'UI Preferences'),
|
|
307
|
+
Icon: ScreenIcon,
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
key: 'limits',
|
|
311
|
+
label: t('settings.ramLimits', 'RAM & Limits'),
|
|
312
|
+
Icon: BrainIcon,
|
|
313
|
+
},
|
|
314
|
+
].map(tab => {
|
|
315
|
+
const isActive = settingsActiveSubTab === tab.key;
|
|
316
|
+
const IconComp = tab.Icon;
|
|
317
|
+
return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="tab" accessibilityLabel={tab.label} accessibilityState={{ selected: isActive }} onPress={() => {
|
|
318
|
+
animateNextLayout();
|
|
319
|
+
setSettingsActiveSubTab(tab.key);
|
|
320
|
+
}} style={{
|
|
321
|
+
paddingVertical: 8,
|
|
322
|
+
paddingHorizontal: 14,
|
|
323
|
+
flexDirection: 'row',
|
|
324
|
+
alignItems: 'center',
|
|
325
|
+
justifyContent: 'center',
|
|
326
|
+
gap: 6,
|
|
327
|
+
borderRadius: 9,
|
|
328
|
+
backgroundColor: isActive
|
|
329
|
+
? AppColors.purple
|
|
330
|
+
: 'transparent',
|
|
331
|
+
}}>
|
|
332
|
+
<IconComp color={isActive ? AppColors.white : AppColors.grayText} size={13}/>
|
|
333
|
+
<Text style={{
|
|
334
|
+
fontFamily: AppFonts.interBold,
|
|
335
|
+
fontSize: 12.5,
|
|
336
|
+
lineHeight: 16,
|
|
337
|
+
color: isActive
|
|
338
|
+
? AppColors.white
|
|
339
|
+
: AppColors.grayText,
|
|
340
|
+
}}>
|
|
341
|
+
{tab.label}
|
|
342
|
+
</Text>
|
|
343
|
+
{tab.badge && (<View style={{
|
|
344
|
+
backgroundColor: isActive
|
|
345
|
+
? 'rgba(255,255,255,0.25)'
|
|
346
|
+
: `${AppColors.purple}18`,
|
|
347
|
+
paddingHorizontal: 5.5,
|
|
348
|
+
paddingVertical: 1,
|
|
349
|
+
borderRadius: 10,
|
|
350
|
+
}}>
|
|
351
|
+
<Text style={{
|
|
352
|
+
fontFamily: AppFonts.interBold,
|
|
353
|
+
fontSize: 9.5,
|
|
354
|
+
color: isActive
|
|
355
|
+
? AppColors.white
|
|
356
|
+
: AppColors.purple,
|
|
357
|
+
}}>
|
|
358
|
+
{tab.badge}
|
|
359
|
+
</Text>
|
|
360
|
+
</View>)}
|
|
361
|
+
</TouchableScale>);
|
|
362
|
+
})}
|
|
363
|
+
</ScrollView>
|
|
379
364
|
</View>
|
|
380
365
|
|
|
381
366
|
{settingsActiveSubTab === 'module' && (<View style={{ gap: 12 }}>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import React, { useState, useEffect, useMemo, useCallback } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
|
|
2
2
|
import { View, Text, ScrollView, FlatList, TextInput, Modal, Alert, StyleSheet, ActivityIndicator, Platform, } from 'react-native';
|
|
3
3
|
import TouchableScale from '../TouchableScale';
|
|
4
|
+
import globalStyles from '../../styles';
|
|
4
5
|
import { AppColors } from '../../styles/AppColors';
|
|
5
6
|
import { AppFonts } from '../../styles/AppFonts';
|
|
6
7
|
import { useTranslation } from '../../i18n';
|
|
7
|
-
import { DatabaseIcon, SearchIcon, ClearIcon, PlusIcon, PencilIcon, TrashIcon, CopyIcon, CheckIcon, LayersIcon, ResetIcon, } from '../NetworkIcons';
|
|
8
|
+
import { DatabaseIcon, SearchIcon, ClearIcon, PlusIcon, PencilIcon, TrashIcon, CopyIcon, CheckIcon, LayersIcon, ResetIcon, ChevronIcon, } from '../NetworkIcons';
|
|
8
9
|
import { fetchStorageEntries, setStorageEntry, removeStorageEntry, clearStorageDriver, isAsyncStorageConnected, isMMKVConnected, getRegisteredMMKVInstanceIds, subscribeToStorageChanges, } from '../../customHooks/storageInspector';
|
|
9
10
|
import { copyToClipboard } from '../../helpers';
|
|
10
11
|
import { showToast } from '../../helpers/toast';
|
|
@@ -95,6 +96,7 @@ const StorageEntryCard = React.memo(function StorageEntryCard({ entry, isExpande
|
|
|
95
96
|
});
|
|
96
97
|
export const StorageTab = React.memo(() => {
|
|
97
98
|
const { t } = useTranslation();
|
|
99
|
+
const listRef = useRef(null);
|
|
98
100
|
const [activeDriver, setActiveDriver] = useState('asyncStorage');
|
|
99
101
|
const [activeMMKVId, setActiveMMKVId] = useState('default');
|
|
100
102
|
const [entries, setEntries] = useState([]);
|
|
@@ -360,19 +362,43 @@ export const StorageTab = React.memo(() => {
|
|
|
360
362
|
{isLoading ? (<View style={styles.loadingContainer}>
|
|
361
363
|
<ActivityIndicator size="small" color={AppColors.purple}/>
|
|
362
364
|
<Text style={styles.loadingText}>Loading storage entries...</Text>
|
|
363
|
-
</View>) : (
|
|
364
|
-
|
|
365
|
-
<
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
{
|
|
365
|
+
</View>) : (<>
|
|
366
|
+
<FlatList ref={listRef} data={filteredEntries} keyExtractor={item => item.key} renderItem={renderItem} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={Platform.OS === 'android'} style={styles.scrollArea} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false} ListEmptyComponent={<View style={styles.emptyContainer}>
|
|
367
|
+
<View style={styles.emptyIconWrap}>
|
|
368
|
+
<DatabaseIcon size={28} color={AppColors.grayTextWeak}/>
|
|
369
|
+
</View>
|
|
370
|
+
<Text style={styles.emptyTitle}>
|
|
371
|
+
{search ? 'No matching keys found' : `No ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} Keys`}
|
|
372
|
+
</Text>
|
|
373
|
+
<Text style={styles.emptySubtitle}>
|
|
374
|
+
{search
|
|
372
375
|
? 'Try modifying your search query'
|
|
373
376
|
: `Storage is auto-detected. Tap "+ Add" above to create your first ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} key!`}
|
|
374
|
-
|
|
375
|
-
|
|
377
|
+
</Text>
|
|
378
|
+
</View>} ListFooterComponent={<View style={{ height: 60 }}/>}/>
|
|
379
|
+
|
|
380
|
+
<TouchableScale onPress={() => {
|
|
381
|
+
try {
|
|
382
|
+
listRef.current?.scrollToOffset({
|
|
383
|
+
offset: 0,
|
|
384
|
+
animated: true,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
try {
|
|
389
|
+
listRef.current?.scrollToIndex({
|
|
390
|
+
index: 0,
|
|
391
|
+
animated: true,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
catch { }
|
|
395
|
+
}
|
|
396
|
+
}} hitSlop={12} style={globalStyles.scrollTopBtn}>
|
|
397
|
+
<View style={{ transform: [{ rotate: '180deg' }] }}>
|
|
398
|
+
<ChevronIcon color={AppColors.white} size={18}/>
|
|
399
|
+
</View>
|
|
400
|
+
</TouchableScale>
|
|
401
|
+
</>)}
|
|
376
402
|
|
|
377
403
|
|
|
378
404
|
<Modal visible={modalVisible} transparent animationType="fade" onRequestClose={() => setModalVisible(false)}>
|
|
@@ -32,6 +32,8 @@ export const UpdateAvailableModal = ({ visible, latestVersion, onClose, }) => {
|
|
|
32
32
|
const fadeAnim = useState(new Animated.Value(0))[0];
|
|
33
33
|
const scaleAnim = useState(new Animated.Value(0.92))[0];
|
|
34
34
|
const installCommand = `npm install react-native-inapp-inspector@latest`;
|
|
35
|
+
if (typeof __DEV__ === 'undefined' || !__DEV__)
|
|
36
|
+
return null;
|
|
35
37
|
useEffect(() => {
|
|
36
38
|
if (visible) {
|
|
37
39
|
setCopied(false);
|
|
@@ -4,7 +4,7 @@ import Svg, { Path } from 'react-native-svg';
|
|
|
4
4
|
import { AppColors } from '../styles/AppColors';
|
|
5
5
|
import { METHOD_COLORS } from '../constants';
|
|
6
6
|
import { getStatusColor, getDurationColor, formatDateTime, getSize, } from '../helpers';
|
|
7
|
-
import { CalendarIcon, ClockIcon, SizeIcon, GlobeIcon, CircleCheckIcon, CircleAlertIcon, CircleXIcon, RepeatIcon, } from './NetworkIcons';
|
|
7
|
+
import { CalendarIcon, ClockIcon, SizeIcon, GlobeIcon, CircleCheckIcon, CircleAlertIcon, CircleXIcon, RepeatIcon, PinIcon, } from './NetworkIcons';
|
|
8
8
|
import { AppFonts } from '../styles/AppFonts';
|
|
9
9
|
import styles from '../styles';
|
|
10
10
|
import HighlightText from './HighlightText';
|
|
@@ -310,9 +310,39 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
|
|
|
310
310
|
|
|
311
311
|
|
|
312
312
|
<View style={styles.cardFooterRow}>
|
|
313
|
-
<View style={
|
|
314
|
-
<
|
|
315
|
-
|
|
313
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexShrink: 1, minWidth: 0 }}>
|
|
314
|
+
<View style={styles.cardDateRow}>
|
|
315
|
+
<CalendarIcon color={AppColors.grayTextWeak} size={10}/>
|
|
316
|
+
<Text style={styles.cardDateText}>{triggeredAt}</Text>
|
|
317
|
+
</View>
|
|
318
|
+
|
|
319
|
+
{item.caller && item.caller !== 'Unknown' && (<View style={[
|
|
320
|
+
styles.chip,
|
|
321
|
+
{
|
|
322
|
+
flexDirection: 'row',
|
|
323
|
+
alignItems: 'center',
|
|
324
|
+
gap: 3,
|
|
325
|
+
backgroundColor: `${AppColors.skyBlue}14`,
|
|
326
|
+
borderColor: `${AppColors.skyBlue}30`,
|
|
327
|
+
paddingHorizontal: 5,
|
|
328
|
+
paddingVertical: 1,
|
|
329
|
+
borderRadius: 4,
|
|
330
|
+
flexShrink: 1,
|
|
331
|
+
maxWidth: 160,
|
|
332
|
+
},
|
|
333
|
+
]}>
|
|
334
|
+
<PinIcon color={AppColors.skyBlue} size={8.5}/>
|
|
335
|
+
<Text style={[
|
|
336
|
+
styles.chipText,
|
|
337
|
+
{
|
|
338
|
+
color: AppColors.skyBlue,
|
|
339
|
+
fontSize: 8.5,
|
|
340
|
+
fontFamily: AppFonts.interMedium,
|
|
341
|
+
},
|
|
342
|
+
]} numberOfLines={1} ellipsizeMode="middle">
|
|
343
|
+
{item.caller}
|
|
344
|
+
</Text>
|
|
345
|
+
</View>)}
|
|
316
346
|
</View>
|
|
317
347
|
|
|
318
348
|
<View style={styles.cardFooterRight}>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "2.3.
|
|
1
|
+
export declare const LIB_VERSION = "2.3.9";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = '2.3.
|
|
1
|
+
export const LIB_VERSION = '2.3.9';
|
|
@@ -22,6 +22,8 @@ const IGNORED_URL_PATTERNS = [
|
|
|
22
22
|
/\/status(?:\?|$)/i,
|
|
23
23
|
/127\.0\.0\.1:(?:8081|8082|8083|19000|19001|19002|3000|8000)/i,
|
|
24
24
|
/localhost:(?:8081|8082|8083|19000|19001|19002|3000|8000)\/index\.bundle/i,
|
|
25
|
+
/google-analytics\.com\/mp\/collect/i,
|
|
26
|
+
/analytics\.google\.com/i,
|
|
25
27
|
];
|
|
26
28
|
function shouldIgnoreUrl(url) {
|
|
27
29
|
if (!url)
|
|
@@ -79,6 +79,36 @@ async function getOrCreateClientId() {
|
|
|
79
79
|
return `${Math.floor(100000000 + Math.random() * 900000000)}.${Math.floor(1000000000 + Math.random() * 9000000000)}`;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
function isDeviceEmulator() {
|
|
83
|
+
try {
|
|
84
|
+
if (Platform.OS === 'android') {
|
|
85
|
+
const c = Platform.constants || {};
|
|
86
|
+
const model = String(c.Model || '').toLowerCase();
|
|
87
|
+
const brand = String(c.Brand || '').toLowerCase();
|
|
88
|
+
const fingerprint = String(c.Fingerprint || '').toLowerCase();
|
|
89
|
+
const hardware = String(c.Hardware || '').toLowerCase();
|
|
90
|
+
const manufacturer = String(c.Manufacturer || '').toLowerCase();
|
|
91
|
+
return (model.includes('emulator') ||
|
|
92
|
+
model.includes('sdk') ||
|
|
93
|
+
model.includes('google_sdk') ||
|
|
94
|
+
model.includes('vbox') ||
|
|
95
|
+
brand.includes('generic') ||
|
|
96
|
+
fingerprint.startsWith('generic') ||
|
|
97
|
+
hardware.includes('goldfish') ||
|
|
98
|
+
hardware.includes('ranchu') ||
|
|
99
|
+
manufacturer.includes('genymotion'));
|
|
100
|
+
}
|
|
101
|
+
if (Platform.OS === 'ios') {
|
|
102
|
+
const c = Platform.constants || {};
|
|
103
|
+
const model = String(c.Model || '').toLowerCase();
|
|
104
|
+
return model.includes('simulator') || Boolean(c.isSimulator);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
82
112
|
function getSystemMetadata(environment) {
|
|
83
113
|
const rnConstants = Platform.constants;
|
|
84
114
|
const rnVersion = rnConstants?.reactNativeVersion
|
|
@@ -87,6 +117,7 @@ function getSystemMetadata(environment) {
|
|
|
87
117
|
const isHermes = Boolean(typeof global.HermesInternal === 'object' && global.HermesInternal !== null);
|
|
88
118
|
const isFabric = Boolean(global?.nativeFabricUIManager !== undefined);
|
|
89
119
|
const isDev = Boolean(typeof __DEV__ !== 'undefined' && __DEV__);
|
|
120
|
+
const isEmulator = isDeviceEmulator();
|
|
90
121
|
return {
|
|
91
122
|
lib_version: LIB_VERSION,
|
|
92
123
|
platform: Platform.OS,
|
|
@@ -95,6 +126,9 @@ function getSystemMetadata(environment) {
|
|
|
95
126
|
is_hermes: isHermes,
|
|
96
127
|
is_fabric: isFabric,
|
|
97
128
|
is_dev: isDev,
|
|
129
|
+
is_emulator: isEmulator,
|
|
130
|
+
device_type: isEmulator ? 'emulator' : 'real_device',
|
|
131
|
+
app_mode: isDev ? 'local_mode' : 'bundled_application',
|
|
98
132
|
environment: environment || (isDev ? 'DEV' : 'PROD'),
|
|
99
133
|
engagement_time_msec: 1000,
|
|
100
134
|
};
|
package/dist/esm/index.js
CHANGED
|
@@ -362,6 +362,9 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
362
362
|
return false;
|
|
363
363
|
}, [latestNpmVersion]);
|
|
364
364
|
useEffect(() => {
|
|
365
|
+
if (typeof __DEV__ === 'undefined' || !__DEV__) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
365
368
|
let cancelled = false;
|
|
366
369
|
fetch('https://registry.npmjs.org/react-native-inapp-inspector/latest')
|
|
367
370
|
.then(res => (res.ok ? res.json() : null))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-inapp-inspector",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.9",
|
|
4
4
|
"description": "The zero-config, all-in-one in-app debugger for React Native & Expo. Inspect Network (fetch/axios), Console logs, Stack Traces, Redux State, Firebase Analytics, and JS Bundle size directly on device.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {useCallback, useState, useMemo, useEffect} from 'react';
|
|
1
|
+
import React, {useCallback, useState, useMemo, useEffect, useRef} from 'react';
|
|
2
2
|
import {
|
|
3
3
|
FlatList,
|
|
4
4
|
Pressable,
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
PinIcon,
|
|
56
56
|
MoneyIcon,
|
|
57
57
|
UserCheckIcon,
|
|
58
|
+
ChevronIcon,
|
|
58
59
|
} from '../NetworkIcons';
|
|
59
60
|
|
|
60
61
|
const AnalyticsHeader = React.memo(() => {
|
|
@@ -1090,6 +1091,7 @@ const AnalyticsTab = React.memo(() => {
|
|
|
1090
1091
|
isAnalyticsFilterApplied,
|
|
1091
1092
|
} = useInspector();
|
|
1092
1093
|
|
|
1094
|
+
const listRef = useRef<FlatList>(null);
|
|
1093
1095
|
const [isFilterModalOpen, setIsFilterModalOpen] = useState(false);
|
|
1094
1096
|
|
|
1095
1097
|
const keyExtractor = useCallback(
|
|
@@ -1305,49 +1307,75 @@ const AnalyticsTab = React.memo(() => {
|
|
|
1305
1307
|
style={{flex: 1}}
|
|
1306
1308
|
onLayout={() => setIsAnalyticsLayoutReady(true)}>
|
|
1307
1309
|
{isAnalyticsLayoutReady ? (
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
analyticsSearch
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
ListFooterComponent={
|
|
1336
|
-
filteredAnalyticsEvents.length > 0 ? (
|
|
1337
|
-
<EndOfListFooter
|
|
1338
|
-
count={filteredAnalyticsEvents.length}
|
|
1339
|
-
label="events"
|
|
1310
|
+
<>
|
|
1311
|
+
<FlatList
|
|
1312
|
+
ref={listRef}
|
|
1313
|
+
data={filteredAnalyticsEvents}
|
|
1314
|
+
keyExtractor={keyExtractor}
|
|
1315
|
+
ListHeaderComponent={AnalyticsHeader}
|
|
1316
|
+
renderItem={renderItem}
|
|
1317
|
+
initialNumToRender={12}
|
|
1318
|
+
maxToRenderPerBatch={8}
|
|
1319
|
+
windowSize={5}
|
|
1320
|
+
removeClippedSubviews={true}
|
|
1321
|
+
renderToHardwareTextureAndroid={true}
|
|
1322
|
+
ListEmptyComponent={
|
|
1323
|
+
<EmptyState
|
|
1324
|
+
isSearch={analyticsSearch.length > 0}
|
|
1325
|
+
searchQuery={analyticsSearch}
|
|
1326
|
+
customTitle={
|
|
1327
|
+
analyticsSearch.length > 0
|
|
1328
|
+
? 'No matching analytics events'
|
|
1329
|
+
: 'No analytics events yet'
|
|
1330
|
+
}
|
|
1331
|
+
customSub={
|
|
1332
|
+
analyticsSearch.length > 0
|
|
1333
|
+
? `No events matched "${analyticsSearch}"`
|
|
1334
|
+
: 'Call setupAnalyticsLogger(analytics()) at app start.'
|
|
1335
|
+
}
|
|
1336
|
+
onClearSearch={() => setAnalyticsSearch('')}
|
|
1340
1337
|
/>
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1338
|
+
}
|
|
1339
|
+
ListFooterComponent={
|
|
1340
|
+
filteredAnalyticsEvents.length > 0 ? (
|
|
1341
|
+
<EndOfListFooter
|
|
1342
|
+
count={filteredAnalyticsEvents.length}
|
|
1343
|
+
label="events"
|
|
1344
|
+
/>
|
|
1345
|
+
) : null
|
|
1346
|
+
}
|
|
1347
|
+
contentContainerStyle={[
|
|
1348
|
+
styles.listContent,
|
|
1349
|
+
filteredAnalyticsEvents.length === 0 && {
|
|
1350
|
+
flexGrow: 1,
|
|
1351
|
+
},
|
|
1352
|
+
]}
|
|
1353
|
+
keyboardShouldPersistTaps="handled"
|
|
1354
|
+
/>
|
|
1355
|
+
|
|
1356
|
+
<TouchableScale
|
|
1357
|
+
onPress={() => {
|
|
1358
|
+
try {
|
|
1359
|
+
listRef.current?.scrollToOffset({
|
|
1360
|
+
offset: 0,
|
|
1361
|
+
animated: true,
|
|
1362
|
+
});
|
|
1363
|
+
} catch {
|
|
1364
|
+
try {
|
|
1365
|
+
listRef.current?.scrollToIndex({
|
|
1366
|
+
index: 0,
|
|
1367
|
+
animated: true,
|
|
1368
|
+
});
|
|
1369
|
+
} catch {}
|
|
1370
|
+
}
|
|
1371
|
+
}}
|
|
1372
|
+
hitSlop={12}
|
|
1373
|
+
style={styles.scrollTopBtn}>
|
|
1374
|
+
<View style={{transform: [{rotate: '180deg'}]}}>
|
|
1375
|
+
<ChevronIcon color={AppColors.white} size={18} />
|
|
1376
|
+
</View>
|
|
1377
|
+
</TouchableScale>
|
|
1378
|
+
</>
|
|
1351
1379
|
) : null}
|
|
1352
1380
|
</View>
|
|
1353
1381
|
</>
|
|
@@ -19,6 +19,7 @@ import HighlightText from '../HighlightText';
|
|
|
19
19
|
import SegmentedTabs from '../SegmentedTabs';
|
|
20
20
|
import AnimatedEntrance from '../AnimatedEntrance';
|
|
21
21
|
import EndOfListFooter from '../EndOfListFooter';
|
|
22
|
+
import FeatureUnderDevNotice from './FeatureUnderDevNotice';
|
|
22
23
|
import {AppColors} from '../../styles/AppColors';
|
|
23
24
|
import {AppFonts} from '../../styles/AppFonts';
|
|
24
25
|
import styles from '../../styles';
|
|
@@ -1400,6 +1401,8 @@ const BundleTab = React.memo(() => {
|
|
|
1400
1401
|
</TouchableScale>
|
|
1401
1402
|
</View>
|
|
1402
1403
|
|
|
1404
|
+
<FeatureUnderDevNotice featureName="Metro Bundle Analyzer" />
|
|
1405
|
+
|
|
1403
1406
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1404
1407
|
{/* ── 1. TAB: OVERVIEW & TREEMAP ───────────────────────────────────────── */}
|
|
1405
1408
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|