react-native-inapp-inspector 1.1.13 → 1.1.14
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/AnalyticsEventCard.js +100 -13
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.d.ts +8 -0
- package/dist/commonjs/customHooks/analyticsLogger.js +42 -1
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.js +237 -353
- package/dist/commonjs/styles/index.d.ts +92 -33
- package/dist/commonjs/styles/index.js +101 -45
- package/dist/esm/components/AnalyticsEventCard.js +100 -13
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.d.ts +8 -0
- package/dist/esm/customHooks/analyticsLogger.js +37 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +235 -355
- package/dist/esm/styles/index.d.ts +92 -33
- package/dist/esm/styles/index.js +101 -45
- package/example/android/app/build.gradle +29 -1
- package/example/android/app/src/main/java/com/example/MainApplication.kt +25 -0
- package/example/android/build.gradle +31 -4
- package/example/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/example/android/gradle.properties +1 -0
- package/example/android/settings.gradle +20 -1
- package/example/package-lock.json +1 -1
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import { formatDateTime, getStatusColor, getNavigationInfo, deduplicateLogs, get
|
|
|
26
26
|
// #5 — settings persistence
|
|
27
27
|
import { loadSettings, saveSettings, setCustomStorage, isPersistentStorageAvailable, clearPersistedSettings, } from './helpers/settingsStore';
|
|
28
28
|
// Assets
|
|
29
|
-
import { EmptyRadarIcon, FailIcon, SearchIcon, ScreenIcon, ClearIcon, SortArrowIcon, FilterIcon, InsightsIcon, GlobeIcon, DownloadIcon, CloseWhite, TrashIcon, WhiteBackNavigation, TerminalIcon, SignalIcon, AnalyticsIcon, SunIcon, MoonIcon, BrandCircleIcon, HtmlIcon, CssIcon, JsIcon, ClockIcon, EyeIcon, CheckIcon, SettingsIcon, RequestIcon, ResponseIcon, HeadersIcon, StatusIcon, ChevronIcon, WipeIcon, LayersIcon, UserIcon, InfoCircleIcon, WarningTriangleIcon, ErrorCircleIcon,
|
|
29
|
+
import { EmptyRadarIcon, FailIcon, SearchIcon, ScreenIcon, ClearIcon, SortArrowIcon, FilterIcon, InsightsIcon, GlobeIcon, DownloadIcon, CloseWhite, TrashIcon, WhiteBackNavigation, TerminalIcon, SignalIcon, AnalyticsIcon, SunIcon, MoonIcon, BrandCircleIcon, HtmlIcon, CssIcon, JsIcon, ClockIcon, EyeIcon, CheckIcon, SettingsIcon, RequestIcon, ResponseIcon, HeadersIcon, StatusIcon, ChevronIcon, WipeIcon, LayersIcon, UserIcon, InfoCircleIcon, WarningTriangleIcon, ErrorCircleIcon, MotionIcon, } from './components/NetworkIcons';
|
|
30
30
|
import ErrorBoundary from './components/ErrorBoundary';
|
|
31
31
|
// Stylesheet
|
|
32
32
|
import { AppColors } from './styles/AppColors';
|
|
@@ -37,8 +37,8 @@ import { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, } from './c
|
|
|
37
37
|
// Console
|
|
38
38
|
import { setupConsoleLogger, clearConsoleLogs, subscribeConsoleLogs, } from './customHooks/consoleLogger';
|
|
39
39
|
import { IGNORED_LOG_PREFIXES } from './customHooks/logFilters';
|
|
40
|
-
import { subscribeAnalyticsEvents, clearAnalyticsEvents, autoSetupAnalyticsLogger, } from './customHooks/analyticsLogger';
|
|
41
|
-
import AnalyticsEventCard
|
|
40
|
+
import { subscribeAnalyticsEvents, clearAnalyticsEvents, autoSetupAnalyticsLogger, getCurrentUserProperties, getCurrentUserId, getDefaultEventParameters, getCollectionEnabled, } from './customHooks/analyticsLogger';
|
|
41
|
+
import AnalyticsEventCard from './components/AnalyticsEventCard';
|
|
42
42
|
import AnalyticsDetail from './components/AnalyticsDetail';
|
|
43
43
|
import { getWebViewLogs, getWebViewNavHistory, getWebViewHtml, getWebViewCss, getWebViewJs, getWebViewHtmlUrl, clearWebViewData, subscribeWebView, } from './customHooks/webViewLogger';
|
|
44
44
|
let OriginalWebView = null;
|
|
@@ -233,10 +233,10 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
233
233
|
const [settingsActiveSubTab, setSettingsActiveSubTab] = useState('module');
|
|
234
234
|
const [insightsActiveSubTab, setInsightsActiveSubTab] = useState('apis');
|
|
235
235
|
const [tabVisibility, setTabVisibility] = useState({
|
|
236
|
-
insights:
|
|
236
|
+
insights: false,
|
|
237
237
|
apis: true,
|
|
238
238
|
logs: true,
|
|
239
|
-
analytics:
|
|
239
|
+
analytics: true,
|
|
240
240
|
webview: false,
|
|
241
241
|
redux: false,
|
|
242
242
|
});
|
|
@@ -256,10 +256,10 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
256
256
|
setModalHeightPercent(90);
|
|
257
257
|
setModalAnimationType('slide');
|
|
258
258
|
setTabVisibility({
|
|
259
|
-
insights:
|
|
259
|
+
insights: false,
|
|
260
260
|
apis: true,
|
|
261
261
|
logs: true,
|
|
262
|
-
analytics:
|
|
262
|
+
analytics: true,
|
|
263
263
|
webview: false,
|
|
264
264
|
redux: false,
|
|
265
265
|
});
|
|
@@ -324,10 +324,10 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
324
324
|
const dt = saved.defaultTab;
|
|
325
325
|
const vis = {
|
|
326
326
|
...{
|
|
327
|
-
insights:
|
|
327
|
+
insights: false,
|
|
328
328
|
apis: true,
|
|
329
329
|
logs: true,
|
|
330
|
-
analytics:
|
|
330
|
+
analytics: true,
|
|
331
331
|
webview: false,
|
|
332
332
|
redux: false,
|
|
333
333
|
},
|
|
@@ -437,7 +437,6 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
437
437
|
});
|
|
438
438
|
};
|
|
439
439
|
const switchActiveTab = useCallback((key) => {
|
|
440
|
-
animateNextLayout();
|
|
441
440
|
setActiveTab(key);
|
|
442
441
|
}, []);
|
|
443
442
|
const navigateFromDashboard = (key) => {
|
|
@@ -491,8 +490,8 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
491
490
|
const [selectedEvent, setSelectedEvent] = useState(null);
|
|
492
491
|
const [analyticsSearch, setAnalyticsSearch] = useState('');
|
|
493
492
|
const [hideScreenView, setHideScreenView] = useState(true);
|
|
494
|
-
const [
|
|
495
|
-
const [
|
|
493
|
+
const [isAnalyticsLayoutReady, setIsAnalyticsLayoutReady] = useState(false);
|
|
494
|
+
const [analyticsHeaderExpanded, setAnalyticsHeaderExpanded] = useState(false);
|
|
496
495
|
const [newEventIds, setNewEventIds] = useState(new Set());
|
|
497
496
|
const prevEventIdsRef = useRef(new Set());
|
|
498
497
|
const [navState, setNavState] = useState(null);
|
|
@@ -688,6 +687,84 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
688
687
|
}).start();
|
|
689
688
|
}
|
|
690
689
|
}, [newLogIds]);
|
|
690
|
+
const renderAnalyticsHeader = () => {
|
|
691
|
+
const userId = getCurrentUserId();
|
|
692
|
+
const userProperties = getCurrentUserProperties();
|
|
693
|
+
const defaultParams = getDefaultEventParameters();
|
|
694
|
+
const isTrackingEnabled = getCollectionEnabled();
|
|
695
|
+
const hasUserProps = Object.keys(userProperties).length > 0;
|
|
696
|
+
const hasDefaultParams = Object.keys(defaultParams).length > 0;
|
|
697
|
+
const totalEvents = filteredAnalyticsEvents.length;
|
|
698
|
+
return (<View style={styles.analyticsHeaderCard}>
|
|
699
|
+
<View style={[styles.analyticsHeaderTop, !analyticsHeaderExpanded && { marginBottom: 0 }]}>
|
|
700
|
+
<View style={{ flex: 1 }}>
|
|
701
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
702
|
+
<Text style={styles.analyticsHeaderTitle}>Session Info</Text>
|
|
703
|
+
<View style={[
|
|
704
|
+
styles.statusDot,
|
|
705
|
+
{ backgroundColor: isTrackingEnabled ? AppColors.greenColor : AppColors.errorColor }
|
|
706
|
+
]}/>
|
|
707
|
+
<Text style={styles.statusText}>
|
|
708
|
+
{isTrackingEnabled ? 'Active' : 'Paused'}
|
|
709
|
+
</Text>
|
|
710
|
+
</View>
|
|
711
|
+
<Text style={styles.analyticsHeaderSubtitle} numberOfLines={1}>
|
|
712
|
+
{userId ? `User ID: ${userId}` : 'Anonymous Session'}
|
|
713
|
+
</Text>
|
|
714
|
+
</View>
|
|
715
|
+
|
|
716
|
+
<TouchableOpacity style={styles.analyticsHeaderToggle} activeOpacity={0.7} onPress={() => {
|
|
717
|
+
animateNextLayout();
|
|
718
|
+
setAnalyticsHeaderExpanded(!analyticsHeaderExpanded);
|
|
719
|
+
}}>
|
|
720
|
+
<Text style={styles.analyticsHeaderToggleText}>
|
|
721
|
+
{analyticsHeaderExpanded ? 'Collapse' : 'Expand'}
|
|
722
|
+
</Text>
|
|
723
|
+
</TouchableOpacity>
|
|
724
|
+
</View>
|
|
725
|
+
|
|
726
|
+
{analyticsHeaderExpanded && (<>
|
|
727
|
+
{/* Stats Row */}
|
|
728
|
+
<View style={styles.analyticsStatsRow}>
|
|
729
|
+
<View style={styles.analyticsStatBox}>
|
|
730
|
+
<Text style={styles.analyticsStatValue}>{totalEvents}</Text>
|
|
731
|
+
<Text style={styles.analyticsStatLabel}>Events</Text>
|
|
732
|
+
</View>
|
|
733
|
+
<View style={styles.analyticsStatBox}>
|
|
734
|
+
<Text style={styles.analyticsStatValue}>
|
|
735
|
+
{Object.keys(userProperties).length}
|
|
736
|
+
</Text>
|
|
737
|
+
<Text style={styles.analyticsStatLabel}>User Props</Text>
|
|
738
|
+
</View>
|
|
739
|
+
<View style={styles.analyticsStatBox}>
|
|
740
|
+
<Text style={styles.analyticsStatValue}>
|
|
741
|
+
{Object.keys(defaultParams).length}
|
|
742
|
+
</Text>
|
|
743
|
+
<Text style={styles.analyticsStatLabel}>Defaults</Text>
|
|
744
|
+
</View>
|
|
745
|
+
</View>
|
|
746
|
+
|
|
747
|
+
{/* Details Section */}
|
|
748
|
+
{(hasUserProps || hasDefaultParams) && (<View style={styles.analyticsHeaderDetails}>
|
|
749
|
+
{hasUserProps && (<View style={{ marginBottom: 10 }}>
|
|
750
|
+
<Text style={styles.detailsGroupTitle}>Active User Properties</Text>
|
|
751
|
+
{Object.entries(userProperties).map(([k, v]) => (<View key={k} style={styles.detailsRow}>
|
|
752
|
+
<Text style={styles.detailsKey} selectable={true}>{k}</Text>
|
|
753
|
+
<Text style={styles.detailsValue} selectable={true}>{String(v)}</Text>
|
|
754
|
+
</View>))}
|
|
755
|
+
</View>)}
|
|
756
|
+
|
|
757
|
+
{hasDefaultParams && (<View>
|
|
758
|
+
<Text style={styles.detailsGroupTitle}>Default Event Parameters</Text>
|
|
759
|
+
{Object.entries(defaultParams).map(([k, v]) => (<View key={k} style={styles.detailsRow}>
|
|
760
|
+
<Text style={styles.detailsKey} selectable={true}>{k}</Text>
|
|
761
|
+
<Text style={styles.detailsValue} selectable={true}>{String(v)}</Text>
|
|
762
|
+
</View>))}
|
|
763
|
+
</View>)}
|
|
764
|
+
</View>)}
|
|
765
|
+
</>)}
|
|
766
|
+
</View>);
|
|
767
|
+
};
|
|
691
768
|
// #6 — every time the inspector is opened, land on the chosen default tab.
|
|
692
769
|
useEffect(() => {
|
|
693
770
|
if (visible) {
|
|
@@ -856,6 +933,11 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
856
933
|
unsubscribeRedux();
|
|
857
934
|
};
|
|
858
935
|
}, []);
|
|
936
|
+
useEffect(() => {
|
|
937
|
+
if (activeTab !== 'analytics') {
|
|
938
|
+
setIsAnalyticsLayoutReady(false);
|
|
939
|
+
}
|
|
940
|
+
}, [activeTab]);
|
|
859
941
|
useEffect(() => {
|
|
860
942
|
setReqExpanded(undefined);
|
|
861
943
|
setResExpanded(undefined);
|
|
@@ -1199,15 +1281,6 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
1199
1281
|
analytics: `${searchedLogs.filter(l => l.message.toLowerCase().includes('[analytics error]')).length}/${total}`,
|
|
1200
1282
|
};
|
|
1201
1283
|
}, [visibleConsoleLogs, logSearch]);
|
|
1202
|
-
const topEventsArray = useMemo(() => {
|
|
1203
|
-
const freq = {};
|
|
1204
|
-
filteredAnalyticsEvents.forEach(e => {
|
|
1205
|
-
if (e.name === 'screen_view')
|
|
1206
|
-
return;
|
|
1207
|
-
freq[e.name] = (freq[e.name] || 0) + 1;
|
|
1208
|
-
});
|
|
1209
|
-
return Object.entries(freq).sort((a, b) => b[1] - a[1]);
|
|
1210
|
-
}, [filteredAnalyticsEvents]);
|
|
1211
1284
|
function closeModal() {
|
|
1212
1285
|
animateNextLayout();
|
|
1213
1286
|
setVisible(false);
|
|
@@ -3646,16 +3719,9 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
3646
3719
|
</Animated.View>
|
|
3647
3720
|
</View>
|
|
3648
3721
|
{(logs.length > 0 || analyticsEvents.length > 0) && (<Animated.View style={[
|
|
3649
|
-
styles.
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
]}>
|
|
3653
|
-
<Text style={styles.fabBadgeText}>
|
|
3654
|
-
{logs.length + analyticsEvents.length > 99
|
|
3655
|
-
? '99+'
|
|
3656
|
-
: logs.length + analyticsEvents.length}
|
|
3657
|
-
</Text>
|
|
3658
|
-
</Animated.View>)}
|
|
3722
|
+
styles.fabGreenDot,
|
|
3723
|
+
{ transform: [{ scale: unreadPulseAnim }] },
|
|
3724
|
+
]}/>)}
|
|
3659
3725
|
</TouchableScale>
|
|
3660
3726
|
</Animated.View>
|
|
3661
3727
|
|
|
@@ -3877,108 +3943,108 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
3877
3943
|
</TouchableScale>) : null}
|
|
3878
3944
|
</View>
|
|
3879
3945
|
|
|
3880
|
-
<View style={styles.headerCenter}>
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3946
|
+
{(selected != null || selectedEvent != null) && (<View style={styles.headerCenter}>
|
|
3947
|
+
{selected != null ? (<View style={styles.headerDetailCenter}>
|
|
3948
|
+
<View style={styles.headerDetailRow}>
|
|
3949
|
+
<View style={[
|
|
3950
|
+
styles.headerMethodBadge,
|
|
3951
|
+
{
|
|
3952
|
+
backgroundColor: METHOD_COLORS[selected.method] ??
|
|
3953
|
+
AppColors.grayText,
|
|
3954
|
+
},
|
|
3955
|
+
]}>
|
|
3956
|
+
<Text style={styles.headerMethodText}>
|
|
3957
|
+
{selected.method}
|
|
3958
|
+
</Text>
|
|
3959
|
+
</View>
|
|
3960
|
+
<Text style={styles.headerDetailTitle} numberOfLines={1} ellipsizeMode="middle">
|
|
3961
|
+
{detailTitle}
|
|
3892
3962
|
</Text>
|
|
3893
3963
|
</View>
|
|
3894
|
-
<
|
|
3895
|
-
{
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3964
|
+
<View style={styles.headerDetailSubRow}>
|
|
3965
|
+
<View style={{
|
|
3966
|
+
flexDirection: 'row',
|
|
3967
|
+
alignItems: 'center',
|
|
3968
|
+
gap: 5,
|
|
3969
|
+
paddingHorizontal: 8,
|
|
3970
|
+
paddingVertical: 3,
|
|
3971
|
+
borderRadius: 20,
|
|
3972
|
+
backgroundColor: `${getStatusColor(selected.status)}26`,
|
|
3973
|
+
borderWidth: 1,
|
|
3974
|
+
borderColor: `${getStatusColor(selected.status)}55`,
|
|
3975
|
+
}}>
|
|
3976
|
+
<View style={[
|
|
3977
|
+
styles.headerStatusDot,
|
|
3978
|
+
{
|
|
3979
|
+
backgroundColor: getStatusColor(selected.status),
|
|
3980
|
+
},
|
|
3981
|
+
]}/>
|
|
3982
|
+
<Text style={[
|
|
3983
|
+
styles.headerSubTitle,
|
|
3984
|
+
{ fontFamily: AppFonts.interBold },
|
|
3985
|
+
]}>
|
|
3986
|
+
{selected.status === 0
|
|
3987
|
+
? 'Failed'
|
|
3988
|
+
: selected.status ?? 'Pending'}
|
|
3989
|
+
</Text>
|
|
3990
|
+
</View>
|
|
3991
|
+
<View style={{
|
|
3992
|
+
flexDirection: 'row',
|
|
3993
|
+
alignItems: 'center',
|
|
3994
|
+
gap: 4,
|
|
3995
|
+
paddingHorizontal: 8,
|
|
3996
|
+
paddingVertical: 3,
|
|
3997
|
+
borderRadius: 20,
|
|
3998
|
+
backgroundColor: 'rgba(255,255,255,0.16)',
|
|
3999
|
+
}}>
|
|
4000
|
+
<ClockIcon color="#FFFFFF" size={11}/>
|
|
4001
|
+
<Text style={styles.headerSubTitle}>
|
|
4002
|
+
{selected.duration != null
|
|
4003
|
+
? `${selected.duration}ms`
|
|
4004
|
+
: '—'}
|
|
4005
|
+
</Text>
|
|
4006
|
+
</View>
|
|
4007
|
+
</View>
|
|
4008
|
+
</View>) : selectedEvent != null ? (<View style={styles.headerDetailCenter}>
|
|
4009
|
+
<View style={styles.headerDetailRow}>
|
|
3910
4010
|
<View style={[
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
4011
|
+
styles.headerMethodBadge,
|
|
4012
|
+
{
|
|
4013
|
+
backgroundColor: selectedEvent.source === 'firebase'
|
|
4014
|
+
? 'rgba(224,123,26,0.3)'
|
|
4015
|
+
: 'rgba(124,92,191,0.3)',
|
|
4016
|
+
},
|
|
4017
|
+
]}>
|
|
4018
|
+
<Text style={styles.headerMethodText}>
|
|
4019
|
+
{selectedEvent.source === 'firebase'
|
|
4020
|
+
? 'FB'
|
|
4021
|
+
: 'MAN'}
|
|
4022
|
+
</Text>
|
|
4023
|
+
</View>
|
|
4024
|
+
<Text style={styles.headerDetailTitle} numberOfLines={1} ellipsizeMode="middle">
|
|
4025
|
+
{selectedEvent.name}
|
|
3923
4026
|
</Text>
|
|
3924
4027
|
</View>
|
|
3925
|
-
<View style={
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
<ClockIcon color="#FFFFFF" size={11}/>
|
|
4028
|
+
<View style={styles.headerDetailSubRow}>
|
|
4029
|
+
<View style={[
|
|
4030
|
+
styles.headerStatusDot,
|
|
4031
|
+
{
|
|
4032
|
+
backgroundColor: selectedEvent.source === 'firebase'
|
|
4033
|
+
? '#E07B1A'
|
|
4034
|
+
: AppColors.purple,
|
|
4035
|
+
},
|
|
4036
|
+
]}/>
|
|
3935
4037
|
<Text style={styles.headerSubTitle}>
|
|
3936
|
-
{
|
|
3937
|
-
|
|
3938
|
-
|
|
4038
|
+
{Object.keys(selectedEvent.params).length} param
|
|
4039
|
+
{Object.keys(selectedEvent.params).length !== 1
|
|
4040
|
+
? 's'
|
|
4041
|
+
: ''}
|
|
4042
|
+
{' · '}
|
|
4043
|
+
{selectedEvent.source}
|
|
3939
4044
|
</Text>
|
|
3940
4045
|
</View>
|
|
3941
|
-
</View>
|
|
3942
|
-
|
|
3943
|
-
<View style={styles.headerDetailRow}>
|
|
3944
|
-
<View style={[
|
|
3945
|
-
styles.headerMethodBadge,
|
|
3946
|
-
{
|
|
3947
|
-
backgroundColor: selectedEvent.source === 'firebase'
|
|
3948
|
-
? 'rgba(224,123,26,0.3)'
|
|
3949
|
-
: 'rgba(124,92,191,0.3)',
|
|
3950
|
-
},
|
|
3951
|
-
]}>
|
|
3952
|
-
<Text style={styles.headerMethodText}>
|
|
3953
|
-
{selectedEvent.source === 'firebase'
|
|
3954
|
-
? 'FB'
|
|
3955
|
-
: 'MAN'}
|
|
3956
|
-
</Text>
|
|
3957
|
-
</View>
|
|
3958
|
-
<Text style={styles.headerDetailTitle} numberOfLines={1} ellipsizeMode="middle">
|
|
3959
|
-
{selectedEvent.name}
|
|
3960
|
-
</Text>
|
|
3961
|
-
</View>
|
|
3962
|
-
<View style={styles.headerDetailSubRow}>
|
|
3963
|
-
<View style={[
|
|
3964
|
-
styles.headerStatusDot,
|
|
3965
|
-
{
|
|
3966
|
-
backgroundColor: selectedEvent.source === 'firebase'
|
|
3967
|
-
? '#E07B1A'
|
|
3968
|
-
: AppColors.purple,
|
|
3969
|
-
},
|
|
3970
|
-
]}/>
|
|
3971
|
-
<Text style={styles.headerSubTitle}>
|
|
3972
|
-
{Object.keys(selectedEvent.params).length} param
|
|
3973
|
-
{Object.keys(selectedEvent.params).length !== 1
|
|
3974
|
-
? 's'
|
|
3975
|
-
: ''}
|
|
3976
|
-
{' · '}
|
|
3977
|
-
{selectedEvent.source}
|
|
3978
|
-
</Text>
|
|
3979
|
-
</View>
|
|
3980
|
-
</View>) : null}
|
|
3981
|
-
</View>
|
|
4046
|
+
</View>) : null}
|
|
4047
|
+
</View>)}
|
|
3982
4048
|
|
|
3983
4049
|
<View style={[
|
|
3984
4050
|
styles.headerRight,
|
|
@@ -4146,7 +4212,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4146
4212
|
{/* ─── Search + Shared Toolbar for Analytics ──────────────────────── */}
|
|
4147
4213
|
<View style={[
|
|
4148
4214
|
styles.toolbarRow,
|
|
4149
|
-
{ marginTop: 12, marginBottom:
|
|
4215
|
+
{ marginTop: 12, marginBottom: 8 },
|
|
4150
4216
|
]}>
|
|
4151
4217
|
<View style={styles.searchContainer}>
|
|
4152
4218
|
<SearchIcon color={AppColors.grayTextWeak} size={16}/>
|
|
@@ -4155,194 +4221,24 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4155
4221
|
<ClearIcon color={AppColors.grayTextWeak} size={14}/>
|
|
4156
4222
|
</Pressable>)}
|
|
4157
4223
|
</View>
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
alignItems: 'center',
|
|
4162
|
-
gap: 4,
|
|
4163
|
-
paddingHorizontal: 10,
|
|
4164
|
-
paddingVertical: 5,
|
|
4165
|
-
borderRadius: 8,
|
|
4166
|
-
backgroundColor: 'rgba(255,46,87,0.06)',
|
|
4167
|
-
borderWidth: 1,
|
|
4168
|
-
borderColor: 'rgba(255,46,87,0.15)',
|
|
4169
|
-
}} onPress={handleDelete} hitSlop={6}>
|
|
4170
|
-
<WipeIcon color={AppColors.errorColor} size={13}/>
|
|
4171
|
-
<Text style={{
|
|
4172
|
-
fontFamily: AppFonts.interBold,
|
|
4173
|
-
fontSize: 10.5,
|
|
4174
|
-
color: AppColors.errorColor,
|
|
4175
|
-
}}>
|
|
4176
|
-
Clear
|
|
4177
|
-
</Text>
|
|
4178
|
-
</TouchableScale>
|
|
4179
|
-
</View>)}
|
|
4180
|
-
</View>
|
|
4181
|
-
|
|
4182
|
-
{/* ─── Secondary Tab Bar for Analytics ──────────────────────── */}
|
|
4183
|
-
<View style={{
|
|
4184
|
-
marginHorizontal: 16,
|
|
4185
|
-
marginTop: 4,
|
|
4186
|
-
marginBottom: 8,
|
|
4187
|
-
backgroundColor: AppColors.grayBackground,
|
|
4188
|
-
borderRadius: 8,
|
|
4189
|
-
padding: 4,
|
|
4190
|
-
flexDirection: 'row',
|
|
4191
|
-
borderWidth: 1,
|
|
4192
|
-
borderColor: AppColors.grayBorderSecondary,
|
|
4193
|
-
}}>
|
|
4194
|
-
<Pressable style={[
|
|
4224
|
+
<View style={styles.toolbarRight}>
|
|
4225
|
+
<TouchableScale style={[
|
|
4226
|
+
styles.toolbarBtn,
|
|
4195
4227
|
{
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
borderRadius: 6,
|
|
4199
|
-
alignItems: 'center',
|
|
4200
|
-
},
|
|
4201
|
-
analyticsSubTab === 'ga_events' && {
|
|
4202
|
-
backgroundColor: AppColors.primaryLight,
|
|
4203
|
-
shadowColor: '#000',
|
|
4204
|
-
shadowOpacity: 0.1,
|
|
4205
|
-
shadowRadius: 3,
|
|
4206
|
-
shadowOffset: { width: 0, height: 1 },
|
|
4207
|
-
elevation: 2,
|
|
4208
|
-
},
|
|
4209
|
-
]} onPress={() => {
|
|
4210
|
-
animateNextLayout();
|
|
4211
|
-
setAnalyticsSubTab('ga_events');
|
|
4212
|
-
}}>
|
|
4213
|
-
<View style={{
|
|
4214
|
-
flexDirection: 'row',
|
|
4215
|
-
alignItems: 'center',
|
|
4216
|
-
gap: 6,
|
|
4217
|
-
}}>
|
|
4218
|
-
{/* #7 */}
|
|
4219
|
-
<AnalyticsIcon size={13} color={analyticsSubTab === 'ga_events'
|
|
4220
|
-
? AppColors.purple
|
|
4221
|
-
: AppColors.grayTextStrong}/>
|
|
4222
|
-
<Text style={[
|
|
4223
|
-
{
|
|
4224
|
-
fontFamily: AppFonts.interMedium,
|
|
4225
|
-
fontSize: 13,
|
|
4226
|
-
color: AppColors.grayTextStrong,
|
|
4227
|
-
},
|
|
4228
|
-
analyticsSubTab === 'ga_events' && {
|
|
4229
|
-
fontFamily: AppFonts.interBold,
|
|
4230
|
-
color: AppColors.purple,
|
|
4231
|
-
},
|
|
4232
|
-
]}>
|
|
4233
|
-
GA Events (
|
|
4234
|
-
{analyticsSearch
|
|
4235
|
-
? filteredAnalyticsEvents.length
|
|
4236
|
-
: analyticsEvents.length}
|
|
4237
|
-
)
|
|
4238
|
-
</Text>
|
|
4239
|
-
</View>
|
|
4240
|
-
</Pressable>
|
|
4241
|
-
<Pressable style={[
|
|
4242
|
-
{
|
|
4243
|
-
flex: 1,
|
|
4244
|
-
paddingVertical: 8,
|
|
4245
|
-
borderRadius: 6,
|
|
4246
|
-
alignItems: 'center',
|
|
4247
|
-
},
|
|
4248
|
-
analyticsSubTab === 'top_events' && {
|
|
4249
|
-
backgroundColor: AppColors.primaryLight,
|
|
4250
|
-
shadowColor: '#000',
|
|
4251
|
-
shadowOpacity: 0.1,
|
|
4252
|
-
shadowRadius: 3,
|
|
4253
|
-
shadowOffset: { width: 0, height: 1 },
|
|
4254
|
-
elevation: 2,
|
|
4255
|
-
},
|
|
4256
|
-
]} onPress={() => {
|
|
4257
|
-
animateNextLayout();
|
|
4258
|
-
setAnalyticsSubTab('top_events');
|
|
4259
|
-
}}>
|
|
4260
|
-
<View style={{
|
|
4261
|
-
flexDirection: 'row',
|
|
4262
|
-
alignItems: 'center',
|
|
4263
|
-
gap: 6,
|
|
4264
|
-
}}>
|
|
4265
|
-
{/* #7 */}
|
|
4266
|
-
<TrendingUpIcon size={13} color={analyticsSubTab === 'top_events'
|
|
4267
|
-
? AppColors.purple
|
|
4268
|
-
: AppColors.grayTextStrong}/>
|
|
4269
|
-
<Text style={[
|
|
4270
|
-
{
|
|
4271
|
-
fontFamily: AppFonts.interMedium,
|
|
4272
|
-
fontSize: 13,
|
|
4273
|
-
color: AppColors.grayTextStrong,
|
|
4274
|
-
},
|
|
4275
|
-
analyticsSubTab === 'top_events' && {
|
|
4276
|
-
fontFamily: AppFonts.interBold,
|
|
4277
|
-
color: AppColors.purple,
|
|
4228
|
+
borderColor: 'rgba(255,46,87,0.22)',
|
|
4229
|
+
backgroundColor: 'rgba(255,46,87,0.06)',
|
|
4278
4230
|
},
|
|
4279
|
-
]}>
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
</Pressable>
|
|
4231
|
+
]} onPress={handleDelete} hitSlop={6}>
|
|
4232
|
+
<WipeIcon color={AppColors.errorColor} size={15}/>
|
|
4233
|
+
</TouchableScale>
|
|
4234
|
+
</View>
|
|
4284
4235
|
</View>
|
|
4285
4236
|
</View>)}
|
|
4286
4237
|
|
|
4287
4238
|
{isReady ? (activeTab === 'insights' ? (<ScrollView style={styles.insightsContainer} contentContainerStyle={styles.insightsContent} showsVerticalScrollIndicator={false}>
|
|
4288
4239
|
{renderInsightsDashboard()}
|
|
4289
|
-
</ScrollView>) : activeTab === 'analytics' ? (<View style={{ flex: 1 }}>
|
|
4290
|
-
{selectedEvent != null ? (<AnalyticsDetail event={selectedEvent}/>) :
|
|
4291
|
-
styles.listContent,
|
|
4292
|
-
{ paddingHorizontal: 16, paddingTop: 12 },
|
|
4293
|
-
]} renderItem={({ item: [name, count], index }) => {
|
|
4294
|
-
const maxCount = topEventsArray[0]?.[1] || 1;
|
|
4295
|
-
const pct = Math.max(6, (count / maxCount) * 100);
|
|
4296
|
-
const color = getEventColor(name);
|
|
4297
|
-
return (<AnimatedEntrance index={index} distance={8} style={[
|
|
4298
|
-
styles.analyticsTopEventsCard,
|
|
4299
|
-
{ marginBottom: 6, paddingVertical: 10, paddingHorizontal: 12 },
|
|
4300
|
-
]}>
|
|
4301
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
|
|
4302
|
-
<Text style={{
|
|
4303
|
-
fontFamily: AppFonts.interBold,
|
|
4304
|
-
fontSize: 11,
|
|
4305
|
-
color: color,
|
|
4306
|
-
width: 18,
|
|
4307
|
-
textAlign: 'center',
|
|
4308
|
-
}}>
|
|
4309
|
-
{index + 1}
|
|
4310
|
-
</Text>
|
|
4311
|
-
<View style={{ flex: 1, gap: 4 }}>
|
|
4312
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
4313
|
-
<Text style={{
|
|
4314
|
-
fontFamily: AppFonts.interMedium,
|
|
4315
|
-
fontSize: 12.5,
|
|
4316
|
-
color: AppColors.primaryBlack,
|
|
4317
|
-
flex: 1,
|
|
4318
|
-
}} numberOfLines={1}>
|
|
4319
|
-
{name}
|
|
4320
|
-
</Text>
|
|
4321
|
-
<Text style={{
|
|
4322
|
-
fontFamily: AppFonts.interBold,
|
|
4323
|
-
fontSize: 12,
|
|
4324
|
-
color: color,
|
|
4325
|
-
marginLeft: 8,
|
|
4326
|
-
}}>
|
|
4327
|
-
{count}
|
|
4328
|
-
</Text>
|
|
4329
|
-
</View>
|
|
4330
|
-
<View style={{ height: 3, backgroundColor: AppColors.grayBackground, borderRadius: 2, overflow: 'hidden' }}>
|
|
4331
|
-
<LinearGradient colors={[color, `${color}88`]} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={{
|
|
4332
|
-
height: '100%',
|
|
4333
|
-
borderRadius: 2,
|
|
4334
|
-
width: `${pct}%`,
|
|
4335
|
-
}}/>
|
|
4336
|
-
</View>
|
|
4337
|
-
</View>
|
|
4338
|
-
</View>
|
|
4339
|
-
</AnimatedEntrance>);
|
|
4340
|
-
}} ListEmptyComponent={<View style={styles.emptyContainer}>
|
|
4341
|
-
<View style={styles.emptyIconWrap}>
|
|
4342
|
-
<EmptyRadarIcon color={AppColors.purple} size={32}/>
|
|
4343
|
-
</View>
|
|
4344
|
-
<Text style={styles.emptyTitle}>No Top Events</Text>
|
|
4345
|
-
</View>}/>) : (<FlatList data={filteredAnalyticsEvents} keyExtractor={item => item.id.toString()} renderItem={({ item, index }) => {
|
|
4240
|
+
</ScrollView>) : activeTab === 'analytics' ? (<View style={{ flex: 1 }} onLayout={() => setIsAnalyticsLayoutReady(true)}>
|
|
4241
|
+
{selectedEvent != null ? (<AnalyticsDetail event={selectedEvent}/>) : isAnalyticsLayoutReady ? (<FlatList data={filteredAnalyticsEvents} keyExtractor={(item, index) => item?.id?.toString() ?? index.toString()} ListHeaderComponent={renderAnalyticsHeader} renderItem={({ item, index }) => {
|
|
4346
4242
|
const prev = filteredAnalyticsEvents[index + 1];
|
|
4347
4243
|
const next = filteredAnalyticsEvents[index - 1];
|
|
4348
4244
|
const msSincePrev = prev
|
|
@@ -4353,12 +4249,13 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4353
4249
|
? Math.floor(next.timestamp / 60000)
|
|
4354
4250
|
: -1;
|
|
4355
4251
|
const showTimestamp = index === 0 || thisMin !== nextMin;
|
|
4356
|
-
return (<
|
|
4357
|
-
<AnalyticsEventCard event={item} onPress={() => {
|
|
4252
|
+
return (<AnalyticsEventCard event={item} onPress={() => {
|
|
4358
4253
|
animateNextLayout();
|
|
4359
4254
|
setSelectedEvent(item);
|
|
4360
4255
|
}} isNew={newEventIds.has(item.id)} searchStr={analyticsSearch} isFirst={index === 0} isLast={index === filteredAnalyticsEvents.length - 1} msSincePrev={msSincePrev} showTimestamp={showTimestamp} computedScreenName={(() => {
|
|
4361
|
-
|
|
4256
|
+
if (!item)
|
|
4257
|
+
return '';
|
|
4258
|
+
const rawScreenName = item.screenName ||
|
|
4362
4259
|
item.screenClass ||
|
|
4363
4260
|
item.pageTitle ||
|
|
4364
4261
|
item.pageLocation ||
|
|
@@ -4366,6 +4263,9 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4366
4263
|
item.params?.screen_name ||
|
|
4367
4264
|
item.params?.firebase_screen_class ||
|
|
4368
4265
|
item.params?.screen_class;
|
|
4266
|
+
let screenName = typeof rawScreenName === 'string'
|
|
4267
|
+
? rawScreenName
|
|
4268
|
+
: (rawScreenName ? JSON.stringify(rawScreenName) : '');
|
|
4369
4269
|
const routeInfo = logRouteMapRef.current.get(item.id + 1000000);
|
|
4370
4270
|
if (!screenName) {
|
|
4371
4271
|
if (routeInfo &&
|
|
@@ -4375,8 +4275,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4375
4275
|
}
|
|
4376
4276
|
}
|
|
4377
4277
|
return screenName;
|
|
4378
|
-
})()}/>
|
|
4379
|
-
</AnimatedEntrance>);
|
|
4278
|
+
})()}/>);
|
|
4380
4279
|
}} initialNumToRender={20} maxToRenderPerBatch={20} windowSize={5} removeClippedSubviews={false} ListEmptyComponent={<View style={styles.emptyContainer}>
|
|
4381
4280
|
<View style={styles.emptyIconWrap}>
|
|
4382
4281
|
<EmptyRadarIcon color={AppColors.purple} size={32}/>
|
|
@@ -4396,7 +4295,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4396
4295
|
filteredAnalyticsEvents.length === 0 && {
|
|
4397
4296
|
flexGrow: 1,
|
|
4398
4297
|
},
|
|
4399
|
-
]} keyboardShouldPersistTaps="handled"/>)}
|
|
4298
|
+
]} keyboardShouldPersistTaps="handled"/>) : null}
|
|
4400
4299
|
</View>) : activeTab === 'apis' && selected == null ? (<View style={{ flex: 1 }}>
|
|
4401
4300
|
<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 }}>
|
|
4402
4301
|
<View style={styles.toolbarRow}>
|
|
@@ -4409,27 +4308,19 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4409
4308
|
</View>
|
|
4410
4309
|
|
|
4411
4310
|
<View style={styles.toolbarRight}>
|
|
4412
|
-
<TouchableScale style={
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
fontFamily: AppFonts.interBold,
|
|
4426
|
-
fontSize: 10.5,
|
|
4427
|
-
color: AppColors.errorColor,
|
|
4428
|
-
}}>
|
|
4429
|
-
{selectedLogs.size > 0
|
|
4430
|
-
? `Delete (${selectedLogs.size})`
|
|
4431
|
-
: 'Clear'}
|
|
4432
|
-
</Text>
|
|
4311
|
+
<TouchableScale style={[
|
|
4312
|
+
styles.toolbarBtn,
|
|
4313
|
+
{
|
|
4314
|
+
borderColor: 'rgba(255,46,87,0.22)',
|
|
4315
|
+
backgroundColor: 'rgba(255,46,87,0.06)',
|
|
4316
|
+
},
|
|
4317
|
+
]} onPress={handleDelete} hitSlop={6}>
|
|
4318
|
+
<WipeIcon color={AppColors.errorColor} size={15}/>
|
|
4319
|
+
{selectedLogs.size > 0 && (<View style={styles.trashBadge}>
|
|
4320
|
+
<Text style={styles.trashBadgeText}>
|
|
4321
|
+
{selectedLogs.size}
|
|
4322
|
+
</Text>
|
|
4323
|
+
</View>)}
|
|
4433
4324
|
</TouchableScale>
|
|
4434
4325
|
|
|
4435
4326
|
<TouchableScale style={styles.toolbarBtn} onPress={() => setSortOrder(o => o === 'newest' ? 'oldest' : 'newest')} hitSlop={10}>
|
|
@@ -4597,25 +4488,14 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4597
4488
|
<TouchableScale style={styles.toolbarBtn} onPress={() => setLogSortOrder(o => o === 'newest' ? 'oldest' : 'newest')} hitSlop={10}>
|
|
4598
4489
|
<SortArrowIcon color={AppColors.grayTextStrong} size={18} direction={logSortOrder === 'newest' ? 'down' : 'up'}/>
|
|
4599
4490
|
</TouchableScale>
|
|
4600
|
-
<TouchableScale style={
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
borderWidth: 1,
|
|
4609
|
-
borderColor: 'rgba(255,46,87,0.15)',
|
|
4610
|
-
}} onPress={handleDelete} hitSlop={6}>
|
|
4611
|
-
<WipeIcon color={AppColors.errorColor} size={13}/>
|
|
4612
|
-
<Text style={{
|
|
4613
|
-
fontFamily: AppFonts.interBold,
|
|
4614
|
-
fontSize: 10.5,
|
|
4615
|
-
color: AppColors.errorColor,
|
|
4616
|
-
}}>
|
|
4617
|
-
Clear
|
|
4618
|
-
</Text>
|
|
4491
|
+
<TouchableScale style={[
|
|
4492
|
+
styles.toolbarBtn,
|
|
4493
|
+
{
|
|
4494
|
+
borderColor: 'rgba(255,46,87,0.22)',
|
|
4495
|
+
backgroundColor: 'rgba(255,46,87,0.06)',
|
|
4496
|
+
},
|
|
4497
|
+
]} onPress={handleDelete} hitSlop={6}>
|
|
4498
|
+
<WipeIcon color={AppColors.errorColor} size={15}/>
|
|
4619
4499
|
</TouchableScale>
|
|
4620
4500
|
</View>
|
|
4621
4501
|
</View>
|
|
@@ -4886,7 +4766,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, }) => {
|
|
|
4886
4766
|
</ScrollView>
|
|
4887
4767
|
</View>
|
|
4888
4768
|
|
|
4889
|
-
<FlatList data={filteredConsoleLogs} keyExtractor={item => item
|
|
4769
|
+
<FlatList data={filteredConsoleLogs} keyExtractor={(item, index) => item?.id?.toString() ?? index.toString()} ListHeaderComponent={(() => {
|
|
4890
4770
|
const total = visibleConsoleLogs.length;
|
|
4891
4771
|
const filtered = filteredConsoleLogs.length;
|
|
4892
4772
|
const isAllSelected = logFilters.has('all') ||
|
|
@@ -5949,7 +5829,7 @@ export default NetworkInspectorWrapper;
|
|
|
5949
5829
|
// Re-export public APIs
|
|
5950
5830
|
export { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, addAxiosInterceptors, } from './customHooks/networkLogger';
|
|
5951
5831
|
export { setupConsoleLogger, clearConsoleLogs, subscribeConsoleLogs, } from './customHooks/consoleLogger';
|
|
5952
|
-
export { setupAnalyticsLogger, logAnalyticsEvent, subscribeAnalyticsEvents, clearAnalyticsEvents, } from './customHooks/analyticsLogger';
|
|
5832
|
+
export { setupAnalyticsLogger, logAnalyticsEvent, subscribeAnalyticsEvents, clearAnalyticsEvents, getCurrentUserProperties, getCurrentUserId, getDefaultEventParameters, getCollectionEnabled, } from './customHooks/analyticsLogger';
|
|
5953
5833
|
export { WebView, getWebViewLogs, getWebViewNavHistory, getWebViewHtml, getWebViewCss, getWebViewJs, getWebViewHtmlUrl, clearWebViewData, subscribeWebView, } from './customHooks/webViewLogger';
|
|
5954
5834
|
export { default as ErrorBoundary } from './components/ErrorBoundary';
|
|
5955
5835
|
export { connectReduxStore, inspectorReduxMiddleware, getReduxState, subscribeReduxState, getActionHistory, clearActionHistory, } from './customHooks/reduxLogger';
|