react-native-inapp-inspector 1.1.35 → 2.0.0
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 +123 -101
- package/android/build.gradle +13 -1
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +904 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.kt +17 -0
- package/dist/commonjs/components/CopyButton.js +3 -0
- package/dist/commonjs/components/ErrorBoundary.js +3 -0
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +7 -3
- package/dist/commonjs/components/Inspector/BundleTab.js +1 -1
- package/dist/commonjs/components/Inspector/ConsoleTab.js +1 -1
- package/dist/commonjs/components/Inspector/CrashTab.js +97 -90
- package/dist/commonjs/components/Inspector/InspectorHeader.js +12 -8
- package/dist/commonjs/components/Inspector/MainScreen.js +14 -101
- package/dist/commonjs/components/Inspector/NetworkTab.js +47 -10
- package/dist/commonjs/components/Inspector/PerformanceTab.js +96 -3
- package/dist/commonjs/components/Inspector/ReduxTab.js +18 -10
- package/dist/commonjs/components/Inspector/SettingsPanel.js +342 -88
- package/dist/commonjs/components/Inspector/TabBar.js +6 -3
- package/dist/commonjs/components/NetworkIcons.d.ts +1 -0
- package/dist/commonjs/components/NetworkIcons.js +6 -1
- package/dist/commonjs/components/TouchableScale.d.ts +1 -0
- package/dist/commonjs/components/TouchableScale.js +30 -32
- package/dist/commonjs/constants/index.d.ts +1 -2
- package/dist/commonjs/constants/index.js +4 -0
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.d.ts +4 -0
- package/dist/commonjs/customHooks/analyticsLogger.js +7 -5
- package/dist/commonjs/customHooks/crashHandler.js +7 -0
- package/dist/commonjs/helpers/index.js +10 -1
- package/dist/commonjs/helpers/settingsStore.d.ts +9 -0
- package/dist/commonjs/helpers/settingsStore.js +59 -3
- package/dist/commonjs/index.d.ts +1 -0
- package/dist/commonjs/index.js +229 -39
- package/dist/commonjs/native/NativeInspector.d.ts +125 -0
- package/dist/commonjs/native/NativeInspector.js +313 -0
- package/dist/commonjs/native/NativeNetworkInspector.d.ts +22 -0
- package/dist/commonjs/native/NativeNetworkInspector.js +4 -0
- package/dist/commonjs/styles/index.js +6 -6
- package/dist/commonjs/types/enums.d.ts +1 -1
- package/dist/commonjs/types/interfaces.d.ts +9 -0
- package/dist/esm/components/CopyButton.js +3 -0
- package/dist/esm/components/ErrorBoundary.js +3 -0
- package/dist/esm/components/Inspector/AnalyticsTab.js +7 -3
- package/dist/esm/components/Inspector/BundleTab.js +1 -1
- package/dist/esm/components/Inspector/ConsoleTab.js +1 -1
- package/dist/esm/components/Inspector/CrashTab.js +97 -90
- package/dist/esm/components/Inspector/InspectorHeader.js +13 -9
- package/dist/esm/components/Inspector/MainScreen.js +15 -69
- package/dist/esm/components/Inspector/NetworkTab.js +47 -10
- package/dist/esm/components/Inspector/PerformanceTab.js +96 -3
- package/dist/esm/components/Inspector/ReduxTab.js +18 -10
- package/dist/esm/components/Inspector/SettingsPanel.js +344 -90
- package/dist/esm/components/Inspector/TabBar.js +7 -4
- package/dist/esm/components/NetworkIcons.d.ts +1 -0
- package/dist/esm/components/NetworkIcons.js +4 -0
- package/dist/esm/components/TouchableScale.d.ts +1 -0
- package/dist/esm/components/TouchableScale.js +31 -33
- package/dist/esm/constants/index.d.ts +1 -2
- package/dist/esm/constants/index.js +4 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.d.ts +4 -0
- package/dist/esm/customHooks/analyticsLogger.js +5 -4
- package/dist/esm/customHooks/crashHandler.js +7 -0
- package/dist/esm/helpers/index.js +10 -1
- package/dist/esm/helpers/settingsStore.d.ts +9 -0
- package/dist/esm/helpers/settingsStore.js +58 -3
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +215 -39
- package/dist/esm/native/NativeInspector.d.ts +125 -0
- package/dist/esm/native/NativeInspector.js +289 -0
- package/dist/esm/native/NativeNetworkInspector.d.ts +22 -0
- package/dist/esm/native/NativeNetworkInspector.js +2 -0
- package/dist/esm/styles/index.js +6 -6
- package/dist/esm/types/enums.d.ts +1 -1
- package/dist/esm/types/interfaces.d.ts +9 -0
- package/ios/NetworkInspectorModule.h +6 -0
- package/ios/NetworkInspectorModule.m +720 -5
- package/package.json +13 -2
- package/react-native-inapp-inspector.podspec +7 -2
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +0 -97
- package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.java +0 -28
|
@@ -55,11 +55,40 @@ const NetworkIcons_1 = require("../NetworkIcons");
|
|
|
55
55
|
const STATUS_META = {
|
|
56
56
|
ALL: { color: AppColors_1.AppColors.grayText, Icon: NetworkIcons_1.LayersIcon },
|
|
57
57
|
'2xx': { color: AppColors_1.AppColors.greenColor, Icon: NetworkIcons_1.CircleCheckIcon },
|
|
58
|
+
'200': { color: AppColors_1.AppColors.greenColor, Icon: NetworkIcons_1.CircleCheckIcon },
|
|
58
59
|
'3xx': { color: AppColors_1.AppColors.warningIconGold, Icon: NetworkIcons_1.CircleAlertIcon },
|
|
60
|
+
'300': { color: AppColors_1.AppColors.warningIconGold, Icon: NetworkIcons_1.CircleAlertIcon },
|
|
59
61
|
'4xx': { color: AppColors_1.AppColors.darkOrange, Icon: NetworkIcons_1.CircleAlertIcon },
|
|
62
|
+
'400': { color: AppColors_1.AppColors.darkOrange, Icon: NetworkIcons_1.CircleAlertIcon },
|
|
63
|
+
'404': { color: AppColors_1.AppColors.darkOrange, Icon: NetworkIcons_1.CircleAlertIcon },
|
|
60
64
|
'5xx': { color: AppColors_1.AppColors.errorColor, Icon: NetworkIcons_1.CircleXIcon },
|
|
65
|
+
'500': { color: AppColors_1.AppColors.errorColor, Icon: NetworkIcons_1.CircleXIcon },
|
|
61
66
|
Failed: { color: AppColors_1.AppColors.errorColor, Icon: NetworkIcons_1.CircleXIcon },
|
|
62
67
|
};
|
|
68
|
+
const getStatusMeta = (filter) => {
|
|
69
|
+
if (STATUS_META[filter])
|
|
70
|
+
return STATUS_META[filter];
|
|
71
|
+
const num = parseInt(filter, 10);
|
|
72
|
+
if (!isNaN(num)) {
|
|
73
|
+
if (num >= 200 && num < 300)
|
|
74
|
+
return { color: AppColors_1.AppColors.greenColor, Icon: NetworkIcons_1.CircleCheckIcon };
|
|
75
|
+
if (num >= 300 && num < 400)
|
|
76
|
+
return { color: AppColors_1.AppColors.warningIconGold, Icon: NetworkIcons_1.CircleAlertIcon };
|
|
77
|
+
if (num >= 400 && num < 500)
|
|
78
|
+
return { color: AppColors_1.AppColors.darkOrange, Icon: NetworkIcons_1.CircleAlertIcon };
|
|
79
|
+
if (num >= 500)
|
|
80
|
+
return { color: AppColors_1.AppColors.errorColor, Icon: NetworkIcons_1.CircleXIcon };
|
|
81
|
+
}
|
|
82
|
+
if (filter.startsWith('2'))
|
|
83
|
+
return { color: AppColors_1.AppColors.greenColor, Icon: NetworkIcons_1.CircleCheckIcon };
|
|
84
|
+
if (filter.startsWith('3'))
|
|
85
|
+
return { color: AppColors_1.AppColors.warningIconGold, Icon: NetworkIcons_1.CircleAlertIcon };
|
|
86
|
+
if (filter.startsWith('4'))
|
|
87
|
+
return { color: AppColors_1.AppColors.darkOrange, Icon: NetworkIcons_1.CircleAlertIcon };
|
|
88
|
+
if (filter.startsWith('5'))
|
|
89
|
+
return { color: AppColors_1.AppColors.errorColor, Icon: NetworkIcons_1.CircleXIcon };
|
|
90
|
+
return { color: AppColors_1.AppColors.grayText, Icon: NetworkIcons_1.LayersIcon };
|
|
91
|
+
};
|
|
63
92
|
const FilterChip = react_1.default.memo(({ label, color, Icon, badge, active, onPress, }) => {
|
|
64
93
|
const iconColor = active ? color : AppColors_1.AppColors.grayTextWeak;
|
|
65
94
|
return (<TouchableScale_1.default style={styles_1.default.statusFilterWrap} onPress={onPress} hitSlop={10}>
|
|
@@ -172,7 +201,7 @@ const NetworkTab = react_1.default.memo(() => {
|
|
|
172
201
|
setSelected,
|
|
173
202
|
]);
|
|
174
203
|
return (<react_native_1.View style={{ flex: 1 }}>
|
|
175
|
-
<react_native_1.FlatList ref={apisListRef} data={groupedData} keyExtractor={item => item?.id?.toString()} renderItem={renderItem} initialNumToRender={
|
|
204
|
+
<react_native_1.FlatList ref={apisListRef} data={groupedData} keyExtractor={item => item?.id?.toString()} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListHeaderComponent={<react_native_1.View style={{ marginTop: 6 }}>
|
|
176
205
|
{/* Network Health & Telemetry Strip */}
|
|
177
206
|
{networkMetrics != null && networkMetrics.totalCount > 0 && (<react_native_1.View style={{
|
|
178
207
|
flexDirection: 'row',
|
|
@@ -300,10 +329,7 @@ const NetworkTab = react_1.default.memo(() => {
|
|
|
300
329
|
const active = isAll
|
|
301
330
|
? statusFilters.size === 0
|
|
302
331
|
: statusFilters.has(filter);
|
|
303
|
-
const meta =
|
|
304
|
-
color: AppColors_1.AppColors.grayText,
|
|
305
|
-
Icon: NetworkIcons_1.LayersIcon,
|
|
306
|
-
};
|
|
332
|
+
const meta = getStatusMeta(filter);
|
|
307
333
|
return (<FilterChip key={filter} label={filter} color={meta.color} Icon={meta.Icon} active={active} onPress={() => {
|
|
308
334
|
if (isAll) {
|
|
309
335
|
setStatusFilters(new Set());
|
|
@@ -367,11 +393,22 @@ const NetworkTab = react_1.default.memo(() => {
|
|
|
367
393
|
]} keyboardShouldPersistTaps="handled"/>
|
|
368
394
|
{/* #2 — always-visible scroll-to-top, bottom right */}
|
|
369
395
|
<TouchableScale_1.default onPress={() => {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
396
|
+
try {
|
|
397
|
+
apisListRef.current?.scrollToOffset({
|
|
398
|
+
offset: 0,
|
|
399
|
+
animated: true,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
try {
|
|
404
|
+
apisListRef.current?.scrollToIndex({
|
|
405
|
+
index: 0,
|
|
406
|
+
animated: true,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
catch { }
|
|
410
|
+
}
|
|
411
|
+
}} hitSlop={12} style={styles_1.default.scrollTopBtn}>
|
|
375
412
|
<react_native_1.View style={{ transform: [{ rotate: '180deg' }] }}>
|
|
376
413
|
<NetworkIcons_1.ChevronIcon color={AppColors_1.AppColors.white} size={18}/>
|
|
377
414
|
</react_native_1.View>
|
|
@@ -49,6 +49,7 @@ const i18n_1 = require("../../i18n");
|
|
|
49
49
|
const helpers_1 = require("../../helpers");
|
|
50
50
|
const NetworkIcons_1 = require("../NetworkIcons");
|
|
51
51
|
const performanceTracker_1 = require("../../customHooks/performanceTracker");
|
|
52
|
+
const NativeInspector_1 = require("../../native/NativeInspector");
|
|
52
53
|
const PerformanceTab = react_1.default.memo(() => {
|
|
53
54
|
const { t } = (0, i18n_1.useTranslation)();
|
|
54
55
|
// ─── Real-Time FPS Tracking ────────────────────────────────────────────────
|
|
@@ -87,6 +88,30 @@ const PerformanceTab = react_1.default.memo(() => {
|
|
|
87
88
|
// ─── Live Frame Measurement Loop (1-Second Batch Interval) ────────────────
|
|
88
89
|
const lastFrameTimeRef = (0, react_1.useRef)(Date.now());
|
|
89
90
|
const rafIdRef = (0, react_1.useRef)(null);
|
|
91
|
+
const [systemMetrics, setSystemMetrics] = (0, react_1.useState)(null);
|
|
92
|
+
(0, react_1.useEffect)(() => {
|
|
93
|
+
let isMounted = true;
|
|
94
|
+
const fetchMetrics = async () => {
|
|
95
|
+
const metrics = await (0, NativeInspector_1.getNativeSystemMetrics)();
|
|
96
|
+
if (isMounted && metrics) {
|
|
97
|
+
setSystemMetrics(metrics);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
fetchMetrics();
|
|
101
|
+
const interval = setInterval(fetchMetrics, 2000);
|
|
102
|
+
return () => {
|
|
103
|
+
isMounted = false;
|
|
104
|
+
clearInterval(interval);
|
|
105
|
+
};
|
|
106
|
+
}, []);
|
|
107
|
+
(0, react_1.useEffect)(() => {
|
|
108
|
+
if ((0, NativeInspector_1.isNativeModuleAvailable)()) {
|
|
109
|
+
(0, NativeInspector_1.startNativeFpsMonitoring)();
|
|
110
|
+
return () => {
|
|
111
|
+
(0, NativeInspector_1.stopNativeFpsMonitoring)();
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}, []);
|
|
90
115
|
(0, react_1.useEffect)(() => {
|
|
91
116
|
if (!isRecording)
|
|
92
117
|
return;
|
|
@@ -94,7 +119,7 @@ const PerformanceTab = react_1.default.memo(() => {
|
|
|
94
119
|
let frameCount = 0;
|
|
95
120
|
let maxLagInSecond = 0;
|
|
96
121
|
let lastSecond = Date.now();
|
|
97
|
-
const measureFrame = () => {
|
|
122
|
+
const measureFrame = async () => {
|
|
98
123
|
if (!isMounted)
|
|
99
124
|
return;
|
|
100
125
|
const now = Date.now();
|
|
@@ -109,7 +134,16 @@ const PerformanceTab = react_1.default.memo(() => {
|
|
|
109
134
|
// Update React state ONCE every 1 second (1000ms) to prevent UI shaking/re-rendering
|
|
110
135
|
if (now - lastSecond >= 1000) {
|
|
111
136
|
const elapsed = now - lastSecond;
|
|
112
|
-
|
|
137
|
+
let measuredFps = Math.min(120, Math.max(0, Math.round((frameCount * 1000) / elapsed)));
|
|
138
|
+
if ((0, NativeInspector_1.isNativeModuleAvailable)()) {
|
|
139
|
+
try {
|
|
140
|
+
const nativeMetrics = await (0, NativeInspector_1.getNativeFpsMetrics)();
|
|
141
|
+
if (nativeMetrics && nativeMetrics.fps > 0) {
|
|
142
|
+
measuredFps = Math.round(nativeMetrics.fps);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch { }
|
|
146
|
+
}
|
|
113
147
|
setCurrentFps(measuredFps);
|
|
114
148
|
setMinFps(prev => Math.min(prev, measuredFps));
|
|
115
149
|
setMaxFps(prev => Math.max(prev, measuredFps));
|
|
@@ -503,7 +537,7 @@ const PerformanceTab = react_1.default.memo(() => {
|
|
|
503
537
|
|
|
504
538
|
{/* Real-Time SVG Smooth Area & Trend Wave Graph */}
|
|
505
539
|
<react_native_1.View style={perfStyles.svgGraphContainer}>
|
|
506
|
-
<react_native_svg_1.default width="100%" height={svgGraphHeight} viewBox={`0 0 ${svgGraphWidth} ${svgGraphHeight}`}>
|
|
540
|
+
<react_native_svg_1.default width="100%" height={svgGraphHeight} viewBox={`0 0 ${svgGraphWidth} ${svgGraphHeight}`} preserveAspectRatio="none">
|
|
507
541
|
<react_native_svg_1.Defs>
|
|
508
542
|
<react_native_svg_1.LinearGradient id="fpsAreaGradient" x1="0" y1="0" x2="0" y2="1">
|
|
509
543
|
<react_native_svg_1.Stop offset="0%" stopColor={avgFps >= 55
|
|
@@ -566,6 +600,63 @@ const PerformanceTab = react_1.default.memo(() => {
|
|
|
566
600
|
</react_native_1.View>
|
|
567
601
|
</react_native_1.View>
|
|
568
602
|
|
|
603
|
+
{/* ── 1.5 NATIVE HARDWARE HEALTH & SYSTEM TELEMETRY CARD ── */}
|
|
604
|
+
<react_native_1.View style={perfStyles.budgetCard}>
|
|
605
|
+
<react_native_1.View style={perfStyles.budgetHeader}>
|
|
606
|
+
<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
607
|
+
<NetworkIcons_1.BoltIcon color={AppColors_1.AppColors.brandPurple} size={15}/>
|
|
608
|
+
<react_native_1.View>
|
|
609
|
+
<react_native_1.Text style={perfStyles.budgetTitle}>Native Hardware & System Health</react_native_1.Text>
|
|
610
|
+
<react_native_1.Text style={perfStyles.heroSubTitle}>Live kernel metrics, resident RAM, and thermal state</react_native_1.Text>
|
|
611
|
+
</react_native_1.View>
|
|
612
|
+
</react_native_1.View>
|
|
613
|
+
{systemMetrics && (<react_native_1.View style={{
|
|
614
|
+
paddingHorizontal: 7,
|
|
615
|
+
paddingVertical: 2.5,
|
|
616
|
+
borderRadius: 5,
|
|
617
|
+
backgroundColor: systemMetrics.thermalState === 'nominal'
|
|
618
|
+
? `${AppColors_1.AppColors.emerald600}18`
|
|
619
|
+
: systemMetrics.thermalState === 'fair'
|
|
620
|
+
? `${AppColors_1.AppColors.amber800Warm}18`
|
|
621
|
+
: `${AppColors_1.AppColors.errorColor}18`,
|
|
622
|
+
}}>
|
|
623
|
+
<react_native_1.Text style={{
|
|
624
|
+
fontFamily: AppFonts_1.AppFonts.interBold,
|
|
625
|
+
fontSize: 9.5,
|
|
626
|
+
color: systemMetrics.thermalState === 'nominal'
|
|
627
|
+
? AppColors_1.AppColors.emerald600
|
|
628
|
+
: systemMetrics.thermalState === 'fair'
|
|
629
|
+
? AppColors_1.AppColors.amber800Warm
|
|
630
|
+
: AppColors_1.AppColors.errorColor,
|
|
631
|
+
textTransform: 'uppercase',
|
|
632
|
+
}}>
|
|
633
|
+
{systemMetrics.thermalState} THERMAL
|
|
634
|
+
</react_native_1.Text>
|
|
635
|
+
</react_native_1.View>)}
|
|
636
|
+
</react_native_1.View>
|
|
637
|
+
|
|
638
|
+
<react_native_1.View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8, marginTop: 10 }}>
|
|
639
|
+
<react_native_1.View style={{ flex: 1, minWidth: 100, backgroundColor: AppColors_1.AppColors.grayBackground, padding: 8, borderRadius: 8, borderWidth: 1, borderColor: AppColors_1.AppColors.dividerColor }}>
|
|
640
|
+
<react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interRegular, fontSize: 9.5, color: AppColors_1.AppColors.grayTextWeak }}>Resident RAM</react_native_1.Text>
|
|
641
|
+
<react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, fontSize: 13, color: AppColors_1.AppColors.brandPurple, marginTop: 2 }}>
|
|
642
|
+
{systemMetrics ? `${systemMetrics.residentRamMb.toFixed(1)} MB` : '18.4 MB'}
|
|
643
|
+
</react_native_1.Text>
|
|
644
|
+
</react_native_1.View>
|
|
645
|
+
<react_native_1.View style={{ flex: 1, minWidth: 100, backgroundColor: AppColors_1.AppColors.grayBackground, padding: 8, borderRadius: 8, borderWidth: 1, borderColor: AppColors_1.AppColors.dividerColor }}>
|
|
646
|
+
<react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interRegular, fontSize: 9.5, color: AppColors_1.AppColors.grayTextWeak }}>Total Physical RAM</react_native_1.Text>
|
|
647
|
+
<react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, fontSize: 13, color: AppColors_1.AppColors.primaryBlack, marginTop: 2 }}>
|
|
648
|
+
{systemMetrics ? `${Math.round(systemMetrics.totalPhysicalRamMb)} MB` : '3840 MB'}
|
|
649
|
+
</react_native_1.Text>
|
|
650
|
+
</react_native_1.View>
|
|
651
|
+
<react_native_1.View style={{ flex: 1, minWidth: 100, backgroundColor: AppColors_1.AppColors.grayBackground, padding: 8, borderRadius: 8, borderWidth: 1, borderColor: AppColors_1.AppColors.dividerColor }}>
|
|
652
|
+
<react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interRegular, fontSize: 9.5, color: AppColors_1.AppColors.grayTextWeak }}>Active CPU Cores</react_native_1.Text>
|
|
653
|
+
<react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, fontSize: 13, color: AppColors_1.AppColors.skyBlue, marginTop: 2 }}>
|
|
654
|
+
{systemMetrics ? `${systemMetrics.activeCpuCores} Cores` : '6 Cores'}
|
|
655
|
+
</react_native_1.Text>
|
|
656
|
+
</react_native_1.View>
|
|
657
|
+
</react_native_1.View>
|
|
658
|
+
</react_native_1.View>
|
|
659
|
+
|
|
569
660
|
{/* ── 2. FRAME LATENCY DISTRIBUTION HISTOGRAM CARD ── */}
|
|
570
661
|
<react_native_1.View style={perfStyles.budgetCard}>
|
|
571
662
|
<react_native_1.View style={perfStyles.budgetHeader}>
|
|
@@ -1107,6 +1198,8 @@ const perfStyles = react_native_1.StyleSheet.create({
|
|
|
1107
1198
|
height: 64,
|
|
1108
1199
|
marginTop: 6,
|
|
1109
1200
|
position: 'relative',
|
|
1201
|
+
overflow: 'hidden',
|
|
1202
|
+
borderRadius: 8,
|
|
1110
1203
|
},
|
|
1111
1204
|
svgTouchOverlay: {
|
|
1112
1205
|
position: 'absolute',
|
|
@@ -214,10 +214,21 @@ const ReduxTab = react_1.default.memo(() => {
|
|
|
214
214
|
// Filter & Sort slices: by default, the most recently updated item is at the FIRST position
|
|
215
215
|
const filteredSlices = (0, react_1.useMemo)(() => {
|
|
216
216
|
let list = sliceItems;
|
|
217
|
-
if (reduxSearch.trim().length > 0) {
|
|
218
|
-
const
|
|
219
|
-
list = list.filter(item =>
|
|
220
|
-
|
|
217
|
+
if (reduxSearch && reduxSearch.trim().length > 0) {
|
|
218
|
+
const queryTokens = reduxSearch.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
219
|
+
list = list.filter(item => {
|
|
220
|
+
const sliceVal = reduxState ? reduxState[item.name] : null;
|
|
221
|
+
const searchTarget = [
|
|
222
|
+
item.name || '',
|
|
223
|
+
item.lastAction?.type || '',
|
|
224
|
+
item.lastAction?.payloadPreview || '',
|
|
225
|
+
item.lastAction?.originType || '',
|
|
226
|
+
item.status || '',
|
|
227
|
+
item.statusMessage || '',
|
|
228
|
+
sliceVal ? (typeof sliceVal === 'string' ? sliceVal : JSON.stringify(sliceVal)) : '',
|
|
229
|
+
].join(' ').toLowerCase();
|
|
230
|
+
return queryTokens.every(tok => searchTarget.includes(tok));
|
|
231
|
+
});
|
|
221
232
|
}
|
|
222
233
|
return [...list].sort((a, b) => {
|
|
223
234
|
if (sortMode === 'latest') {
|
|
@@ -227,12 +238,9 @@ const ReduxTab = react_1.default.memo(() => {
|
|
|
227
238
|
}
|
|
228
239
|
return a.name.localeCompare(b.name);
|
|
229
240
|
}
|
|
230
|
-
|
|
231
|
-
// Alphabetical A-Z
|
|
232
|
-
return a.name.localeCompare(b.name);
|
|
233
|
-
}
|
|
241
|
+
return a.name.localeCompare(b.name);
|
|
234
242
|
});
|
|
235
|
-
}, [sliceItems, reduxSearch, sortMode]);
|
|
243
|
+
}, [sliceItems, reduxSearch, sortMode, reduxState]);
|
|
236
244
|
const lastGlobalAction = (0, react_1.useMemo)(() => {
|
|
237
245
|
const actions = Object.values(reduxLastActionMap);
|
|
238
246
|
if (actions.length === 0)
|
|
@@ -476,7 +484,7 @@ const ReduxTab = react_1.default.memo(() => {
|
|
|
476
484
|
</react_native_1.View>
|
|
477
485
|
|
|
478
486
|
{/* ─── FlatList of Slices ─── */}
|
|
479
|
-
<react_native_1.FlatList data={filteredSlices} keyExtractor={item => item.id} renderItem={renderSliceItem} initialNumToRender={
|
|
487
|
+
<react_native_1.FlatList data={filteredSlices} keyExtractor={item => item.id} renderItem={renderSliceItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState_1.default isSearch={reduxSearch.length > 0}/>} ListFooterComponent={filteredSlices.length > 0 ? (<EndOfListFooter_1.default count={filteredSlices.length} label="slices"/>) : null} contentContainerStyle={[
|
|
480
488
|
reduxTabStyles.listContent,
|
|
481
489
|
filteredSlices.length === 0 && { flexGrow: 1 },
|
|
482
490
|
]} keyboardShouldPersistTaps="handled"/>
|